mstro-app 0.1.47
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/LICENSE +21 -0
- package/README.md +177 -0
- package/bin/commands/config.js +145 -0
- package/bin/commands/login.js +313 -0
- package/bin/commands/logout.js +75 -0
- package/bin/commands/status.js +197 -0
- package/bin/commands/whoami.js +161 -0
- package/bin/configure-claude.js +298 -0
- package/bin/mstro.js +581 -0
- package/bin/postinstall.js +45 -0
- package/bin/release.sh +110 -0
- package/dist/server/cli/headless/claude-invoker.d.ts +17 -0
- package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -0
- package/dist/server/cli/headless/claude-invoker.js +311 -0
- package/dist/server/cli/headless/claude-invoker.js.map +1 -0
- package/dist/server/cli/headless/index.d.ts +13 -0
- package/dist/server/cli/headless/index.d.ts.map +1 -0
- package/dist/server/cli/headless/index.js +10 -0
- package/dist/server/cli/headless/index.js.map +1 -0
- package/dist/server/cli/headless/mcp-config.d.ts +11 -0
- package/dist/server/cli/headless/mcp-config.d.ts.map +1 -0
- package/dist/server/cli/headless/mcp-config.js +76 -0
- package/dist/server/cli/headless/mcp-config.js.map +1 -0
- package/dist/server/cli/headless/output-utils.d.ts +33 -0
- package/dist/server/cli/headless/output-utils.d.ts.map +1 -0
- package/dist/server/cli/headless/output-utils.js +101 -0
- package/dist/server/cli/headless/output-utils.js.map +1 -0
- package/dist/server/cli/headless/prompt-utils.d.ts +21 -0
- package/dist/server/cli/headless/prompt-utils.d.ts.map +1 -0
- package/dist/server/cli/headless/prompt-utils.js +84 -0
- package/dist/server/cli/headless/prompt-utils.js.map +1 -0
- package/dist/server/cli/headless/runner.d.ts +24 -0
- package/dist/server/cli/headless/runner.d.ts.map +1 -0
- package/dist/server/cli/headless/runner.js +99 -0
- package/dist/server/cli/headless/runner.js.map +1 -0
- package/dist/server/cli/headless/types.d.ts +106 -0
- package/dist/server/cli/headless/types.d.ts.map +1 -0
- package/dist/server/cli/headless/types.js +4 -0
- package/dist/server/cli/headless/types.js.map +1 -0
- package/dist/server/cli/improvisation-session-manager.d.ts +155 -0
- package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -0
- package/dist/server/cli/improvisation-session-manager.js +415 -0
- package/dist/server/cli/improvisation-session-manager.js.map +1 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +386 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/mcp/bouncer-cli.d.ts +3 -0
- package/dist/server/mcp/bouncer-cli.d.ts.map +1 -0
- package/dist/server/mcp/bouncer-cli.js +99 -0
- package/dist/server/mcp/bouncer-cli.js.map +1 -0
- package/dist/server/mcp/bouncer-integration.d.ts +36 -0
- package/dist/server/mcp/bouncer-integration.d.ts.map +1 -0
- package/dist/server/mcp/bouncer-integration.js +301 -0
- package/dist/server/mcp/bouncer-integration.js.map +1 -0
- package/dist/server/mcp/security-audit.d.ts +52 -0
- package/dist/server/mcp/security-audit.d.ts.map +1 -0
- package/dist/server/mcp/security-audit.js +118 -0
- package/dist/server/mcp/security-audit.js.map +1 -0
- package/dist/server/mcp/security-patterns.d.ts +73 -0
- package/dist/server/mcp/security-patterns.d.ts.map +1 -0
- package/dist/server/mcp/security-patterns.js +247 -0
- package/dist/server/mcp/security-patterns.js.map +1 -0
- package/dist/server/mcp/server.d.ts +3 -0
- package/dist/server/mcp/server.d.ts.map +1 -0
- package/dist/server/mcp/server.js +146 -0
- package/dist/server/mcp/server.js.map +1 -0
- package/dist/server/routes/files.d.ts +9 -0
- package/dist/server/routes/files.d.ts.map +1 -0
- package/dist/server/routes/files.js +24 -0
- package/dist/server/routes/files.js.map +1 -0
- package/dist/server/routes/improvise.d.ts +3 -0
- package/dist/server/routes/improvise.d.ts.map +1 -0
- package/dist/server/routes/improvise.js +72 -0
- package/dist/server/routes/improvise.js.map +1 -0
- package/dist/server/routes/index.d.ts +10 -0
- package/dist/server/routes/index.d.ts.map +1 -0
- package/dist/server/routes/index.js +12 -0
- package/dist/server/routes/index.js.map +1 -0
- package/dist/server/routes/instances.d.ts +10 -0
- package/dist/server/routes/instances.d.ts.map +1 -0
- package/dist/server/routes/instances.js +47 -0
- package/dist/server/routes/instances.js.map +1 -0
- package/dist/server/routes/notifications.d.ts +3 -0
- package/dist/server/routes/notifications.d.ts.map +1 -0
- package/dist/server/routes/notifications.js +136 -0
- package/dist/server/routes/notifications.js.map +1 -0
- package/dist/server/services/analytics.d.ts +56 -0
- package/dist/server/services/analytics.d.ts.map +1 -0
- package/dist/server/services/analytics.js +240 -0
- package/dist/server/services/analytics.js.map +1 -0
- package/dist/server/services/auth.d.ts +26 -0
- package/dist/server/services/auth.d.ts.map +1 -0
- package/dist/server/services/auth.js +71 -0
- package/dist/server/services/auth.js.map +1 -0
- package/dist/server/services/client-id.d.ts +10 -0
- package/dist/server/services/client-id.d.ts.map +1 -0
- package/dist/server/services/client-id.js +61 -0
- package/dist/server/services/client-id.js.map +1 -0
- package/dist/server/services/credentials.d.ts +39 -0
- package/dist/server/services/credentials.d.ts.map +1 -0
- package/dist/server/services/credentials.js +110 -0
- package/dist/server/services/credentials.js.map +1 -0
- package/dist/server/services/files.d.ts +119 -0
- package/dist/server/services/files.d.ts.map +1 -0
- package/dist/server/services/files.js +560 -0
- package/dist/server/services/files.js.map +1 -0
- package/dist/server/services/instances.d.ts +52 -0
- package/dist/server/services/instances.d.ts.map +1 -0
- package/dist/server/services/instances.js +241 -0
- package/dist/server/services/instances.js.map +1 -0
- package/dist/server/services/pathUtils.d.ts +47 -0
- package/dist/server/services/pathUtils.d.ts.map +1 -0
- package/dist/server/services/pathUtils.js +124 -0
- package/dist/server/services/pathUtils.js.map +1 -0
- package/dist/server/services/platform.d.ts +72 -0
- package/dist/server/services/platform.d.ts.map +1 -0
- package/dist/server/services/platform.js +368 -0
- package/dist/server/services/platform.js.map +1 -0
- package/dist/server/services/sentry.d.ts +5 -0
- package/dist/server/services/sentry.d.ts.map +1 -0
- package/dist/server/services/sentry.js +71 -0
- package/dist/server/services/sentry.js.map +1 -0
- package/dist/server/services/terminal/pty-manager.d.ts +149 -0
- package/dist/server/services/terminal/pty-manager.d.ts.map +1 -0
- package/dist/server/services/terminal/pty-manager.js +377 -0
- package/dist/server/services/terminal/pty-manager.js.map +1 -0
- package/dist/server/services/terminal/tmux-manager.d.ts +82 -0
- package/dist/server/services/terminal/tmux-manager.d.ts.map +1 -0
- package/dist/server/services/terminal/tmux-manager.js +352 -0
- package/dist/server/services/terminal/tmux-manager.js.map +1 -0
- package/dist/server/services/websocket/autocomplete.d.ts +50 -0
- package/dist/server/services/websocket/autocomplete.d.ts.map +1 -0
- package/dist/server/services/websocket/autocomplete.js +361 -0
- package/dist/server/services/websocket/autocomplete.js.map +1 -0
- package/dist/server/services/websocket/file-utils.d.ts +44 -0
- package/dist/server/services/websocket/file-utils.d.ts.map +1 -0
- package/dist/server/services/websocket/file-utils.js +272 -0
- package/dist/server/services/websocket/file-utils.js.map +1 -0
- package/dist/server/services/websocket/handler.d.ts +246 -0
- package/dist/server/services/websocket/handler.d.ts.map +1 -0
- package/dist/server/services/websocket/handler.js +1771 -0
- package/dist/server/services/websocket/handler.js.map +1 -0
- package/dist/server/services/websocket/index.d.ts +11 -0
- package/dist/server/services/websocket/index.d.ts.map +1 -0
- package/dist/server/services/websocket/index.js +14 -0
- package/dist/server/services/websocket/index.js.map +1 -0
- package/dist/server/services/websocket/types.d.ts +214 -0
- package/dist/server/services/websocket/types.d.ts.map +1 -0
- package/dist/server/services/websocket/types.js +4 -0
- package/dist/server/services/websocket/types.js.map +1 -0
- package/dist/server/utils/agent-manager.d.ts +69 -0
- package/dist/server/utils/agent-manager.d.ts.map +1 -0
- package/dist/server/utils/agent-manager.js +269 -0
- package/dist/server/utils/agent-manager.js.map +1 -0
- package/dist/server/utils/paths.d.ts +25 -0
- package/dist/server/utils/paths.d.ts.map +1 -0
- package/dist/server/utils/paths.js +38 -0
- package/dist/server/utils/paths.js.map +1 -0
- package/dist/server/utils/port-manager.d.ts +10 -0
- package/dist/server/utils/port-manager.d.ts.map +1 -0
- package/dist/server/utils/port-manager.js +60 -0
- package/dist/server/utils/port-manager.js.map +1 -0
- package/dist/server/utils/port.d.ts +26 -0
- package/dist/server/utils/port.d.ts.map +1 -0
- package/dist/server/utils/port.js +83 -0
- package/dist/server/utils/port.js.map +1 -0
- package/hooks/bouncer.sh +138 -0
- package/package.json +74 -0
- package/server/README.md +191 -0
- package/server/cli/headless/claude-invoker.ts +415 -0
- package/server/cli/headless/index.ts +39 -0
- package/server/cli/headless/mcp-config.ts +87 -0
- package/server/cli/headless/output-utils.ts +109 -0
- package/server/cli/headless/prompt-utils.ts +108 -0
- package/server/cli/headless/runner.ts +133 -0
- package/server/cli/headless/types.ts +118 -0
- package/server/cli/improvisation-session-manager.ts +531 -0
- package/server/index.ts +456 -0
- package/server/mcp/README.md +122 -0
- package/server/mcp/bouncer-cli.ts +127 -0
- package/server/mcp/bouncer-integration.ts +430 -0
- package/server/mcp/security-audit.ts +180 -0
- package/server/mcp/security-patterns.ts +290 -0
- package/server/mcp/server.ts +174 -0
- package/server/routes/files.ts +29 -0
- package/server/routes/improvise.ts +82 -0
- package/server/routes/index.ts +13 -0
- package/server/routes/instances.ts +54 -0
- package/server/routes/notifications.ts +158 -0
- package/server/services/analytics.ts +277 -0
- package/server/services/auth.ts +80 -0
- package/server/services/client-id.ts +68 -0
- package/server/services/credentials.ts +134 -0
- package/server/services/files.ts +710 -0
- package/server/services/instances.ts +275 -0
- package/server/services/pathUtils.ts +158 -0
- package/server/services/platform.test.ts +1314 -0
- package/server/services/platform.ts +435 -0
- package/server/services/sentry.ts +81 -0
- package/server/services/terminal/pty-manager.ts +464 -0
- package/server/services/terminal/tmux-manager.ts +426 -0
- package/server/services/websocket/autocomplete.ts +438 -0
- package/server/services/websocket/file-utils.ts +305 -0
- package/server/services/websocket/handler.test.ts +20 -0
- package/server/services/websocket/handler.ts +2047 -0
- package/server/services/websocket/index.ts +40 -0
- package/server/services/websocket/types.ts +339 -0
- package/server/tsconfig.json +19 -0
- package/server/utils/agent-manager.ts +323 -0
- package/server/utils/paths.ts +45 -0
- package/server/utils/port-manager.ts +70 -0
- package/server/utils/port.ts +102 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file for details.
|
|
3
|
+
/**
|
|
4
|
+
* Mstro Server (Node.js + Hono)
|
|
5
|
+
*/
|
|
6
|
+
import { randomBytes } from 'node:crypto';
|
|
7
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import { basename, join } from 'node:path';
|
|
9
|
+
import { serve } from '@hono/node-server';
|
|
10
|
+
import { Hono } from 'hono';
|
|
11
|
+
import { cors } from 'hono/cors';
|
|
12
|
+
import { logger } from 'hono/logger';
|
|
13
|
+
import { WebSocketServer } from 'ws';
|
|
14
|
+
// Import route creators
|
|
15
|
+
import { createFileRoutes, createImproviseRoutes, createInstanceRoutes, createNotificationRoutes, createShutdownRoute } from './routes/index.js';
|
|
16
|
+
import { AnalyticsEvents, initAnalytics, shutdownAnalytics, trackEvent } from './services/analytics.js';
|
|
17
|
+
import { AuthService } from './services/auth.js';
|
|
18
|
+
import { FileService } from './services/files.js';
|
|
19
|
+
import { InstanceRegistry } from './services/instances.js';
|
|
20
|
+
import { PlatformConnection } from './services/platform.js';
|
|
21
|
+
import { captureException, flushSentry, initSentry } from './services/sentry.js';
|
|
22
|
+
import { getPTYManager } from './services/terminal/pty-manager.js';
|
|
23
|
+
import { WebSocketImproviseHandler } from './services/websocket/index.js';
|
|
24
|
+
import { findAvailablePort } from './utils/port.js';
|
|
25
|
+
/**
|
|
26
|
+
* Set the terminal tab title
|
|
27
|
+
* Format: "mstro: directory_name"
|
|
28
|
+
* Uses ANSI escape sequence: ESC ] 0 ; title BEL
|
|
29
|
+
*/
|
|
30
|
+
function setTerminalTitle(directory) {
|
|
31
|
+
const dirName = basename(directory) || directory;
|
|
32
|
+
const title = `mstro: ${dirName}`;
|
|
33
|
+
// ESC ] 0 ; title BEL - sets both window title and tab title
|
|
34
|
+
process.stdout.write(`\x1b]0;${title}\x07`);
|
|
35
|
+
}
|
|
36
|
+
// Create Hono app with type inference
|
|
37
|
+
const app = new Hono();
|
|
38
|
+
// Configuration
|
|
39
|
+
const DEFAULT_PORT = 4101;
|
|
40
|
+
const REQUESTED_PORT = process.env.PORT ? parseInt(process.env.PORT, 10) : DEFAULT_PORT;
|
|
41
|
+
const WORKING_DIR = process.env.MSTRO_WORKING_DIR || process.env.WORKING_DIR || process.cwd();
|
|
42
|
+
const IS_PRODUCTION = process.env.NODE_ENV === 'production';
|
|
43
|
+
/**
|
|
44
|
+
* Ensure .claude/settings.json exists with recommended settings
|
|
45
|
+
* for optimal Claude Code performance with Mstro
|
|
46
|
+
*/
|
|
47
|
+
function ensureClaudeSettings(workingDir) {
|
|
48
|
+
const claudeDir = join(workingDir, '.claude');
|
|
49
|
+
const settingsPath = join(claudeDir, 'settings.json');
|
|
50
|
+
// Create .claude directory if it doesn't exist
|
|
51
|
+
if (!existsSync(claudeDir)) {
|
|
52
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
53
|
+
}
|
|
54
|
+
// Recommended settings for Mstro
|
|
55
|
+
const recommendedSettings = {
|
|
56
|
+
env: {
|
|
57
|
+
CLAUDE_CODE_MAX_OUTPUT_TOKENS: "64000",
|
|
58
|
+
DISABLE_NONESSENTIAL_TRAFFIC: "1"
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
// If settings.json doesn't exist, create it
|
|
62
|
+
if (!existsSync(settingsPath)) {
|
|
63
|
+
writeFileSync(settingsPath, JSON.stringify(recommendedSettings, null, 2));
|
|
64
|
+
console.log(`📝 Created .claude/settings.json with recommended settings`);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// If it exists, check if our env settings are present and merge if needed
|
|
68
|
+
try {
|
|
69
|
+
const existingSettings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
70
|
+
let updated = false;
|
|
71
|
+
// Ensure env object exists
|
|
72
|
+
if (!existingSettings.env) {
|
|
73
|
+
existingSettings.env = {};
|
|
74
|
+
updated = true;
|
|
75
|
+
}
|
|
76
|
+
// Add our recommended env settings if they don't exist
|
|
77
|
+
if (!existingSettings.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS) {
|
|
78
|
+
existingSettings.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS = "64000";
|
|
79
|
+
updated = true;
|
|
80
|
+
}
|
|
81
|
+
if (!existingSettings.env.DISABLE_NONESSENTIAL_TRAFFIC) {
|
|
82
|
+
existingSettings.env.DISABLE_NONESSENTIAL_TRAFFIC = "1";
|
|
83
|
+
updated = true;
|
|
84
|
+
}
|
|
85
|
+
if (updated) {
|
|
86
|
+
writeFileSync(settingsPath, JSON.stringify(existingSettings, null, 2));
|
|
87
|
+
console.log(`📝 Updated .claude/settings.json with recommended env settings`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (_e) {
|
|
91
|
+
// If we can't parse the existing file, don't overwrite it
|
|
92
|
+
console.warn(`⚠️ Could not parse existing .claude/settings.json, skipping update`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Ensure Claude settings on startup
|
|
97
|
+
ensureClaudeSettings(WORKING_DIR);
|
|
98
|
+
// Set terminal tab title to show mstro is running and which directory
|
|
99
|
+
setTerminalTitle(WORKING_DIR);
|
|
100
|
+
// Initialize services
|
|
101
|
+
const authService = new AuthService();
|
|
102
|
+
const instanceRegistry = new InstanceRegistry();
|
|
103
|
+
const fileService = new FileService(WORKING_DIR);
|
|
104
|
+
const wsHandler = new WebSocketImproviseHandler();
|
|
105
|
+
// Instance registration deferred to startServer() when port is known
|
|
106
|
+
let _currentInstance;
|
|
107
|
+
// Global middleware
|
|
108
|
+
// In production, restrict CORS to block cross-origin browser requests to localhost.
|
|
109
|
+
// In dev, allow localhost origins on any port for local frontend dev servers.
|
|
110
|
+
app.use('*', cors({
|
|
111
|
+
origin: (origin) => {
|
|
112
|
+
if (!origin)
|
|
113
|
+
return 'http://localhost';
|
|
114
|
+
try {
|
|
115
|
+
const url = new URL(origin);
|
|
116
|
+
if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') {
|
|
117
|
+
return origin;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch { }
|
|
121
|
+
return 'http://localhost';
|
|
122
|
+
}
|
|
123
|
+
}));
|
|
124
|
+
app.use('*', logger());
|
|
125
|
+
// ========================================
|
|
126
|
+
// Authentication Middleware
|
|
127
|
+
// ========================================
|
|
128
|
+
const authMiddleware = async (c, next) => {
|
|
129
|
+
// Skip auth for health check and config
|
|
130
|
+
const publicPaths = ['/health', '/api/config'];
|
|
131
|
+
if (publicPaths.some(path => c.req.path.startsWith(path))) {
|
|
132
|
+
return next();
|
|
133
|
+
}
|
|
134
|
+
// Require the local session token for localhost security.
|
|
135
|
+
// This prevents other local processes or malicious websites from
|
|
136
|
+
// calling the API without the session token from ~/.mstro/session-token.
|
|
137
|
+
const token = c.req.header('x-session-token');
|
|
138
|
+
if (!token || !authService.validateLocalToken(token)) {
|
|
139
|
+
return c.json({ error: 'Unauthorized' }, 401);
|
|
140
|
+
}
|
|
141
|
+
return next();
|
|
142
|
+
};
|
|
143
|
+
app.use('/api/*', authMiddleware);
|
|
144
|
+
// ========================================
|
|
145
|
+
// Health & Configuration
|
|
146
|
+
// ========================================
|
|
147
|
+
// Read version from package.json once at startup
|
|
148
|
+
const PKG_VERSION = (() => {
|
|
149
|
+
try {
|
|
150
|
+
const pkg = JSON.parse(readFileSync(join(import.meta.dirname || '.', '..', 'package.json'), 'utf-8'));
|
|
151
|
+
return pkg.version || '0.0.0';
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return '0.0.0';
|
|
155
|
+
}
|
|
156
|
+
})();
|
|
157
|
+
app.get('/health', (c) => {
|
|
158
|
+
return c.json({
|
|
159
|
+
status: 'ok',
|
|
160
|
+
timestamp: new Date().toISOString(),
|
|
161
|
+
version: PKG_VERSION
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
app.get('/api/config', (c) => {
|
|
165
|
+
return c.json({
|
|
166
|
+
version: PKG_VERSION
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
// ========================================
|
|
170
|
+
// Mount Routes
|
|
171
|
+
// ========================================
|
|
172
|
+
app.route('/api/instances', createInstanceRoutes(instanceRegistry));
|
|
173
|
+
app.route('/api/shutdown', createShutdownRoute(instanceRegistry));
|
|
174
|
+
app.route('/api/improvise', createImproviseRoutes(WORKING_DIR));
|
|
175
|
+
app.route('/api/files', createFileRoutes(fileService));
|
|
176
|
+
app.route('/api/notifications', createNotificationRoutes(WORKING_DIR));
|
|
177
|
+
// ========================================
|
|
178
|
+
// Static File Serving (Production Only)
|
|
179
|
+
// ========================================
|
|
180
|
+
if (IS_PRODUCTION) {
|
|
181
|
+
// For production static file serving, use a reverse proxy like nginx
|
|
182
|
+
// or implement a simple static file middleware if needed
|
|
183
|
+
console.log('Production mode: serve static files via nginx or similar');
|
|
184
|
+
}
|
|
185
|
+
// ========================================
|
|
186
|
+
// 404 & Error Handlers
|
|
187
|
+
// ========================================
|
|
188
|
+
app.notFound((c) => {
|
|
189
|
+
return c.json({ error: 'Not found' }, 404);
|
|
190
|
+
});
|
|
191
|
+
app.onError((err, c) => {
|
|
192
|
+
const errorId = randomBytes(4).toString('hex');
|
|
193
|
+
console.error(`Server error [${errorId}]:`, err);
|
|
194
|
+
captureException(err, { errorId, path: c.req.path, method: c.req.method });
|
|
195
|
+
return c.json({
|
|
196
|
+
error: 'Internal server error',
|
|
197
|
+
errorId,
|
|
198
|
+
message: 'Something went wrong. If this persists, report this error ID to support.'
|
|
199
|
+
}, 500);
|
|
200
|
+
});
|
|
201
|
+
// ========================================
|
|
202
|
+
// Node.js Server with WebSocket Support
|
|
203
|
+
// ========================================
|
|
204
|
+
/**
|
|
205
|
+
* Wrap a ws WebSocket to match our WSContext interface
|
|
206
|
+
*/
|
|
207
|
+
function wrapWebSocket(ws, workingDir) {
|
|
208
|
+
return {
|
|
209
|
+
send: (data) => ws.send(data),
|
|
210
|
+
close: () => ws.close(),
|
|
211
|
+
readyState: ws.readyState,
|
|
212
|
+
_workingDir: workingDir,
|
|
213
|
+
_ws: ws
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Create a virtual WebSocket context that sends responses through the platform relay
|
|
218
|
+
* This allows messages from the web (via platform) to be handled by the same wsHandler
|
|
219
|
+
*/
|
|
220
|
+
function createPlatformRelayContext(platformSend, workingDir) {
|
|
221
|
+
return {
|
|
222
|
+
send: (data) => {
|
|
223
|
+
// Parse the response and send through platform relay
|
|
224
|
+
try {
|
|
225
|
+
const response = typeof data === 'string' ? JSON.parse(data) : JSON.parse(data.toString());
|
|
226
|
+
platformSend(response);
|
|
227
|
+
}
|
|
228
|
+
catch (e) {
|
|
229
|
+
// If not JSON, send as-is (shouldn't happen with our protocol)
|
|
230
|
+
console.error('[PlatformRelay] Failed to parse response:', e);
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
close: () => {
|
|
234
|
+
// No-op for platform relay - connection is managed by PlatformConnection
|
|
235
|
+
},
|
|
236
|
+
readyState: 1, // WebSocket.OPEN
|
|
237
|
+
_workingDir: workingDir,
|
|
238
|
+
_isPlatformRelay: true
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
// Start server with dynamic port selection
|
|
242
|
+
async function startServer() {
|
|
243
|
+
// Initialize error tracking (must be first)
|
|
244
|
+
initSentry();
|
|
245
|
+
// Initialize analytics (fetches config from platform)
|
|
246
|
+
await initAnalytics();
|
|
247
|
+
const PORT = await findAvailablePort(REQUESTED_PORT, 20);
|
|
248
|
+
if (PORT !== REQUESTED_PORT) {
|
|
249
|
+
console.log(`⚠️ Port ${REQUESTED_PORT} in use, using port ${PORT}`);
|
|
250
|
+
}
|
|
251
|
+
_currentInstance = instanceRegistry.register(PORT, WORKING_DIR);
|
|
252
|
+
// Create HTTP server with Hono
|
|
253
|
+
const server = serve({
|
|
254
|
+
fetch: app.fetch,
|
|
255
|
+
port: PORT
|
|
256
|
+
});
|
|
257
|
+
// Create WebSocket server attached to the HTTP server
|
|
258
|
+
const wss = new WebSocketServer({ server: server });
|
|
259
|
+
wss.on('connection', (ws, req) => {
|
|
260
|
+
const url = new URL(req.url || '/', `http://localhost:${PORT}`);
|
|
261
|
+
// Only handle /ws endpoint
|
|
262
|
+
if (url.pathname !== '/ws') {
|
|
263
|
+
ws.close(1008, 'Invalid WebSocket path');
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
// Require local session token for WebSocket connections
|
|
267
|
+
const wsToken = url.searchParams.get('token');
|
|
268
|
+
if (!wsToken || !authService.validateLocalToken(wsToken)) {
|
|
269
|
+
ws.close(4001, 'Unauthorized');
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
// Always use the server's working directory — don't allow clients to override
|
|
273
|
+
const workingDir = WORKING_DIR;
|
|
274
|
+
const wrappedWs = wrapWebSocket(ws, workingDir);
|
|
275
|
+
wsHandler.handleConnection(wrappedWs, workingDir);
|
|
276
|
+
ws.on('message', (data) => {
|
|
277
|
+
const message = typeof data === 'string' ? data : data.toString('utf-8');
|
|
278
|
+
wsHandler.handleMessage(wrappedWs, message, workingDir);
|
|
279
|
+
});
|
|
280
|
+
ws.on('close', () => {
|
|
281
|
+
wsHandler.handleClose(wrappedWs);
|
|
282
|
+
});
|
|
283
|
+
ws.on('error', (error) => {
|
|
284
|
+
console.error('[WebSocket] Error:', error);
|
|
285
|
+
captureException(error, { context: 'websocket.connection' });
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
console.log(`🚀 Mstro Server (Node.js + Hono) on port ${PORT}`);
|
|
289
|
+
console.log(`📁 Working directory: ${WORKING_DIR}`);
|
|
290
|
+
console.log(`Runtime: Node.js ${process.version}`);
|
|
291
|
+
console.log(`Framework: Hono`);
|
|
292
|
+
// Track server started event
|
|
293
|
+
trackEvent(AnalyticsEvents.SERVER_STARTED, { port: PORT });
|
|
294
|
+
// Create a virtual WebSocket context for platform relay
|
|
295
|
+
// This allows messages from the web (via platform) to use the same wsHandler
|
|
296
|
+
let platformRelayContext = null;
|
|
297
|
+
// Queue for messages that arrive before relay context is ready
|
|
298
|
+
// This handles race conditions where initTab arrives before web_connected
|
|
299
|
+
let pendingRelayMessages = [];
|
|
300
|
+
// Connect to platform
|
|
301
|
+
const platformConnection = new PlatformConnection(WORKING_DIR, {
|
|
302
|
+
onConnected: (_connectionId) => {
|
|
303
|
+
console.log(`🎵 Orchestra ready: ${basename(WORKING_DIR)}`);
|
|
304
|
+
// Set up usage reporter to send token usage to platform
|
|
305
|
+
wsHandler.setUsageReporter((report) => {
|
|
306
|
+
platformConnection.send({
|
|
307
|
+
type: 'reportUsage',
|
|
308
|
+
data: report
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
},
|
|
312
|
+
onWebConnected: () => {
|
|
313
|
+
// Create the relay context when web connects
|
|
314
|
+
platformRelayContext = createPlatformRelayContext((message) => platformConnection.send(message), WORKING_DIR);
|
|
315
|
+
// Initialize the connection for the wsHandler
|
|
316
|
+
wsHandler.handleConnection(platformRelayContext, WORKING_DIR);
|
|
317
|
+
// Process any messages that arrived before relay context was ready
|
|
318
|
+
if (pendingRelayMessages.length > 0) {
|
|
319
|
+
for (const message of pendingRelayMessages) {
|
|
320
|
+
wsHandler.handleMessage(platformRelayContext, JSON.stringify(message), WORKING_DIR);
|
|
321
|
+
}
|
|
322
|
+
pendingRelayMessages = [];
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
onWebDisconnected: () => {
|
|
326
|
+
// Clean up when web disconnects
|
|
327
|
+
if (platformRelayContext) {
|
|
328
|
+
wsHandler.handleClose(platformRelayContext);
|
|
329
|
+
platformRelayContext = null;
|
|
330
|
+
}
|
|
331
|
+
// Clear any pending messages
|
|
332
|
+
pendingRelayMessages = [];
|
|
333
|
+
},
|
|
334
|
+
onRelayedMessage: (message) => {
|
|
335
|
+
// Forward messages from web (via platform) to the wsHandler
|
|
336
|
+
if (platformRelayContext) {
|
|
337
|
+
wsHandler.handleMessage(platformRelayContext, JSON.stringify(message), WORKING_DIR);
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
// Queue the message - it will be processed when web_connected arrives
|
|
341
|
+
pendingRelayMessages.push(message);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
platformConnection.connect();
|
|
346
|
+
// Catch unhandled errors at process level
|
|
347
|
+
process.on('uncaughtException', (err) => {
|
|
348
|
+
console.error('[Server] Uncaught exception:', err);
|
|
349
|
+
captureException(err, { context: 'uncaughtException' });
|
|
350
|
+
});
|
|
351
|
+
process.on('unhandledRejection', (reason) => {
|
|
352
|
+
console.error('[Server] Unhandled rejection:', reason);
|
|
353
|
+
captureException(reason instanceof Error ? reason : new Error(String(reason)), { context: 'unhandledRejection' });
|
|
354
|
+
});
|
|
355
|
+
// Cleanup on exit
|
|
356
|
+
process.on('SIGINT', async () => {
|
|
357
|
+
trackEvent(AnalyticsEvents.SERVER_STOPPED);
|
|
358
|
+
await Promise.all([shutdownAnalytics(), flushSentry()]);
|
|
359
|
+
platformConnection.disconnect();
|
|
360
|
+
instanceRegistry.unregister();
|
|
361
|
+
// Close all non-persistent terminal sessions (PTY processes)
|
|
362
|
+
// Note: Persistent (tmux) sessions are intentionally left running
|
|
363
|
+
getPTYManager().closeAll();
|
|
364
|
+
wss.close();
|
|
365
|
+
console.log('\n\n👋 Shutting down gracefully...\n');
|
|
366
|
+
process.exit(0);
|
|
367
|
+
});
|
|
368
|
+
process.on('SIGTERM', async () => {
|
|
369
|
+
trackEvent(AnalyticsEvents.SERVER_STOPPED);
|
|
370
|
+
await Promise.all([shutdownAnalytics(), flushSentry()]);
|
|
371
|
+
platformConnection.disconnect();
|
|
372
|
+
instanceRegistry.unregister();
|
|
373
|
+
// Close all non-persistent terminal sessions (PTY processes)
|
|
374
|
+
// Note: Persistent (tmux) sessions are intentionally left running
|
|
375
|
+
getPTYManager().closeAll();
|
|
376
|
+
wss.close();
|
|
377
|
+
console.log('\n\n👋 Shutting down gracefully...\n');
|
|
378
|
+
process.exit(0);
|
|
379
|
+
});
|
|
380
|
+
// Periodic cleanup
|
|
381
|
+
setInterval(() => {
|
|
382
|
+
wsHandler.cleanupStaleSessions();
|
|
383
|
+
}, 5 * 60 * 1000); // Every 5 minutes
|
|
384
|
+
}
|
|
385
|
+
startServer();
|
|
386
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bouncer-cli.d.ts","sourceRoot":"","sources":["../../../server/mcp/bouncer-cli.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
|
3
|
+
// Licensed under the MIT License. See LICENSE file for details.
|
|
4
|
+
/**
|
|
5
|
+
* Bouncer CLI - Shell-callable wrapper for Mstro security bouncer
|
|
6
|
+
*
|
|
7
|
+
* This CLI reads Claude Code hook input from stdin and returns a security decision.
|
|
8
|
+
* It's designed to be called from bouncer.sh.
|
|
9
|
+
*
|
|
10
|
+
* Input (stdin): Claude Code PreToolUse hook JSON payload
|
|
11
|
+
* Output (stdout): JSON decision { decision: "allow"|"deny", reason: string }
|
|
12
|
+
*
|
|
13
|
+
* The hook payload includes conversation context that we pass to the bouncer
|
|
14
|
+
* so it can make context-aware decisions.
|
|
15
|
+
*/
|
|
16
|
+
import { reviewOperation } from './bouncer-integration.js';
|
|
17
|
+
/**
|
|
18
|
+
* Read all data from stdin (Node.js compatible)
|
|
19
|
+
*/
|
|
20
|
+
async function readStdin() {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const chunks = [];
|
|
23
|
+
process.stdin.on('data', (chunk) => chunks.push(chunk));
|
|
24
|
+
process.stdin.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8').trim()));
|
|
25
|
+
process.stdin.on('error', reject);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function buildOperationString(toolName, toolInput) {
|
|
29
|
+
if (toolName === 'Bash' && toolInput.command) {
|
|
30
|
+
return `${toolName}: ${toolInput.command}`;
|
|
31
|
+
}
|
|
32
|
+
if (['Write', 'Edit', 'Read'].includes(toolName)) {
|
|
33
|
+
const filePath = toolInput.file_path || toolInput.filePath || toolInput.path;
|
|
34
|
+
return filePath ? `${toolName}: ${filePath}` : `${toolName}: ${JSON.stringify(toolInput)}`;
|
|
35
|
+
}
|
|
36
|
+
return `${toolName}: ${JSON.stringify(toolInput)}`;
|
|
37
|
+
}
|
|
38
|
+
function extractConversationContext(hookInput) {
|
|
39
|
+
const lastUserMessage = hookInput.conversation?.last_user_message;
|
|
40
|
+
if (lastUserMessage)
|
|
41
|
+
return `User's request: "${lastUserMessage}"`;
|
|
42
|
+
const recentMessages = hookInput.conversation?.messages?.slice(-5);
|
|
43
|
+
if (recentMessages?.length) {
|
|
44
|
+
return `Recent conversation:\n${recentMessages.map(m => `${m.role}: ${m.content}`).join('\n')}`;
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
async function main() {
|
|
49
|
+
const inputStr = await readStdin();
|
|
50
|
+
if (!inputStr) {
|
|
51
|
+
console.log(JSON.stringify({ decision: 'allow', reason: 'Empty input, allowing' }));
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
let hookInput;
|
|
55
|
+
try {
|
|
56
|
+
hookInput = JSON.parse(inputStr);
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
console.error('[bouncer-cli] Failed to parse input JSON:', e);
|
|
60
|
+
console.log(JSON.stringify({ decision: 'allow', reason: 'Invalid JSON input, allowing' }));
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
63
|
+
const toolName = hookInput.tool_name || hookInput.toolName || 'unknown';
|
|
64
|
+
const toolInput = hookInput.input || hookInput.toolInput || {};
|
|
65
|
+
const userRequestContext = extractConversationContext(hookInput);
|
|
66
|
+
const lastUserMessage = hookInput.conversation?.last_user_message;
|
|
67
|
+
const recentMessages = hookInput.conversation?.messages?.slice(-5);
|
|
68
|
+
const bouncerRequest = {
|
|
69
|
+
operation: buildOperationString(toolName, toolInput),
|
|
70
|
+
context: {
|
|
71
|
+
purpose: userRequestContext || 'Tool use request from Claude',
|
|
72
|
+
workingDirectory: hookInput.working_directory || process.cwd(),
|
|
73
|
+
toolName,
|
|
74
|
+
toolInput,
|
|
75
|
+
userRequest: lastUserMessage,
|
|
76
|
+
conversationHistory: recentMessages?.map(m => `${m.role}: ${m.content}`),
|
|
77
|
+
sessionId: hookInput.session_id,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
try {
|
|
81
|
+
const decision = await reviewOperation(bouncerRequest);
|
|
82
|
+
console.log(JSON.stringify({
|
|
83
|
+
decision: decision.decision === 'deny' ? 'deny' : 'allow',
|
|
84
|
+
reason: decision.reasoning,
|
|
85
|
+
confidence: decision.confidence,
|
|
86
|
+
threatLevel: decision.threatLevel,
|
|
87
|
+
alternative: decision.alternative,
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
console.error('[bouncer-cli] Error:', error.message);
|
|
92
|
+
console.log(JSON.stringify({
|
|
93
|
+
decision: 'allow',
|
|
94
|
+
reason: `Bouncer error: ${error.message}. Allowing to avoid blocking.`
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
main();
|
|
99
|
+
//# sourceMappingURL=bouncer-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bouncer-cli.js","sourceRoot":"","sources":["../../../server/mcp/bouncer-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface BouncerReviewRequest {
|
|
2
|
+
operation: string;
|
|
3
|
+
context?: {
|
|
4
|
+
purpose?: string;
|
|
5
|
+
workingDirectory?: string;
|
|
6
|
+
affectedFiles?: string[];
|
|
7
|
+
alternatives?: string;
|
|
8
|
+
userRequest?: string;
|
|
9
|
+
conversationHistory?: string[];
|
|
10
|
+
sessionId?: string;
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export interface BouncerDecision {
|
|
15
|
+
decision: 'allow' | 'deny' | 'warn_allow';
|
|
16
|
+
confidence: number;
|
|
17
|
+
reasoning: string;
|
|
18
|
+
threatLevel?: 'low' | 'medium' | 'high' | 'critical';
|
|
19
|
+
alternative?: string;
|
|
20
|
+
suggestedCommand?: string;
|
|
21
|
+
enforceable?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Main bouncer review function - 2-layer hybrid system
|
|
25
|
+
*/
|
|
26
|
+
export declare function reviewOperation(request: BouncerReviewRequest): Promise<BouncerDecision>;
|
|
27
|
+
/**
|
|
28
|
+
* Export risk classification utility
|
|
29
|
+
*/
|
|
30
|
+
export { classifyRisk as classifyOperationRisk } from './security-patterns.js';
|
|
31
|
+
/**
|
|
32
|
+
* Launch bouncer agent (legacy compatibility)
|
|
33
|
+
* Redirects to reviewOperation for backward compatibility
|
|
34
|
+
*/
|
|
35
|
+
export declare function launchBouncerAgent(request: BouncerReviewRequest, useAI?: boolean): Promise<BouncerDecision>;
|
|
36
|
+
//# sourceMappingURL=bouncer-integration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bouncer-integration.d.ts","sourceRoot":"","sources":["../../../server/mcp/bouncer-integration.ts"],"names":[],"mappings":"AA2CA,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,YAAY,CAAC,EAAE,MAAM,CAAC;QAEtB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;QAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,YAAY,CAAC;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAyKD;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,CAAC,CAwK7F;AAED;;GAEG;AACH,OAAO,EAAE,YAAY,IAAI,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAE/E;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,oBAAoB,EAC7B,KAAK,GAAE,OAAc,GACpB,OAAO,CAAC,eAAe,CAAC,CAS1B"}
|