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.
Files changed (213) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +177 -0
  3. package/bin/commands/config.js +145 -0
  4. package/bin/commands/login.js +313 -0
  5. package/bin/commands/logout.js +75 -0
  6. package/bin/commands/status.js +197 -0
  7. package/bin/commands/whoami.js +161 -0
  8. package/bin/configure-claude.js +298 -0
  9. package/bin/mstro.js +581 -0
  10. package/bin/postinstall.js +45 -0
  11. package/bin/release.sh +110 -0
  12. package/dist/server/cli/headless/claude-invoker.d.ts +17 -0
  13. package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -0
  14. package/dist/server/cli/headless/claude-invoker.js +311 -0
  15. package/dist/server/cli/headless/claude-invoker.js.map +1 -0
  16. package/dist/server/cli/headless/index.d.ts +13 -0
  17. package/dist/server/cli/headless/index.d.ts.map +1 -0
  18. package/dist/server/cli/headless/index.js +10 -0
  19. package/dist/server/cli/headless/index.js.map +1 -0
  20. package/dist/server/cli/headless/mcp-config.d.ts +11 -0
  21. package/dist/server/cli/headless/mcp-config.d.ts.map +1 -0
  22. package/dist/server/cli/headless/mcp-config.js +76 -0
  23. package/dist/server/cli/headless/mcp-config.js.map +1 -0
  24. package/dist/server/cli/headless/output-utils.d.ts +33 -0
  25. package/dist/server/cli/headless/output-utils.d.ts.map +1 -0
  26. package/dist/server/cli/headless/output-utils.js +101 -0
  27. package/dist/server/cli/headless/output-utils.js.map +1 -0
  28. package/dist/server/cli/headless/prompt-utils.d.ts +21 -0
  29. package/dist/server/cli/headless/prompt-utils.d.ts.map +1 -0
  30. package/dist/server/cli/headless/prompt-utils.js +84 -0
  31. package/dist/server/cli/headless/prompt-utils.js.map +1 -0
  32. package/dist/server/cli/headless/runner.d.ts +24 -0
  33. package/dist/server/cli/headless/runner.d.ts.map +1 -0
  34. package/dist/server/cli/headless/runner.js +99 -0
  35. package/dist/server/cli/headless/runner.js.map +1 -0
  36. package/dist/server/cli/headless/types.d.ts +106 -0
  37. package/dist/server/cli/headless/types.d.ts.map +1 -0
  38. package/dist/server/cli/headless/types.js +4 -0
  39. package/dist/server/cli/headless/types.js.map +1 -0
  40. package/dist/server/cli/improvisation-session-manager.d.ts +155 -0
  41. package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -0
  42. package/dist/server/cli/improvisation-session-manager.js +415 -0
  43. package/dist/server/cli/improvisation-session-manager.js.map +1 -0
  44. package/dist/server/index.d.ts +2 -0
  45. package/dist/server/index.d.ts.map +1 -0
  46. package/dist/server/index.js +386 -0
  47. package/dist/server/index.js.map +1 -0
  48. package/dist/server/mcp/bouncer-cli.d.ts +3 -0
  49. package/dist/server/mcp/bouncer-cli.d.ts.map +1 -0
  50. package/dist/server/mcp/bouncer-cli.js +99 -0
  51. package/dist/server/mcp/bouncer-cli.js.map +1 -0
  52. package/dist/server/mcp/bouncer-integration.d.ts +36 -0
  53. package/dist/server/mcp/bouncer-integration.d.ts.map +1 -0
  54. package/dist/server/mcp/bouncer-integration.js +301 -0
  55. package/dist/server/mcp/bouncer-integration.js.map +1 -0
  56. package/dist/server/mcp/security-audit.d.ts +52 -0
  57. package/dist/server/mcp/security-audit.d.ts.map +1 -0
  58. package/dist/server/mcp/security-audit.js +118 -0
  59. package/dist/server/mcp/security-audit.js.map +1 -0
  60. package/dist/server/mcp/security-patterns.d.ts +73 -0
  61. package/dist/server/mcp/security-patterns.d.ts.map +1 -0
  62. package/dist/server/mcp/security-patterns.js +247 -0
  63. package/dist/server/mcp/security-patterns.js.map +1 -0
  64. package/dist/server/mcp/server.d.ts +3 -0
  65. package/dist/server/mcp/server.d.ts.map +1 -0
  66. package/dist/server/mcp/server.js +146 -0
  67. package/dist/server/mcp/server.js.map +1 -0
  68. package/dist/server/routes/files.d.ts +9 -0
  69. package/dist/server/routes/files.d.ts.map +1 -0
  70. package/dist/server/routes/files.js +24 -0
  71. package/dist/server/routes/files.js.map +1 -0
  72. package/dist/server/routes/improvise.d.ts +3 -0
  73. package/dist/server/routes/improvise.d.ts.map +1 -0
  74. package/dist/server/routes/improvise.js +72 -0
  75. package/dist/server/routes/improvise.js.map +1 -0
  76. package/dist/server/routes/index.d.ts +10 -0
  77. package/dist/server/routes/index.d.ts.map +1 -0
  78. package/dist/server/routes/index.js +12 -0
  79. package/dist/server/routes/index.js.map +1 -0
  80. package/dist/server/routes/instances.d.ts +10 -0
  81. package/dist/server/routes/instances.d.ts.map +1 -0
  82. package/dist/server/routes/instances.js +47 -0
  83. package/dist/server/routes/instances.js.map +1 -0
  84. package/dist/server/routes/notifications.d.ts +3 -0
  85. package/dist/server/routes/notifications.d.ts.map +1 -0
  86. package/dist/server/routes/notifications.js +136 -0
  87. package/dist/server/routes/notifications.js.map +1 -0
  88. package/dist/server/services/analytics.d.ts +56 -0
  89. package/dist/server/services/analytics.d.ts.map +1 -0
  90. package/dist/server/services/analytics.js +240 -0
  91. package/dist/server/services/analytics.js.map +1 -0
  92. package/dist/server/services/auth.d.ts +26 -0
  93. package/dist/server/services/auth.d.ts.map +1 -0
  94. package/dist/server/services/auth.js +71 -0
  95. package/dist/server/services/auth.js.map +1 -0
  96. package/dist/server/services/client-id.d.ts +10 -0
  97. package/dist/server/services/client-id.d.ts.map +1 -0
  98. package/dist/server/services/client-id.js +61 -0
  99. package/dist/server/services/client-id.js.map +1 -0
  100. package/dist/server/services/credentials.d.ts +39 -0
  101. package/dist/server/services/credentials.d.ts.map +1 -0
  102. package/dist/server/services/credentials.js +110 -0
  103. package/dist/server/services/credentials.js.map +1 -0
  104. package/dist/server/services/files.d.ts +119 -0
  105. package/dist/server/services/files.d.ts.map +1 -0
  106. package/dist/server/services/files.js +560 -0
  107. package/dist/server/services/files.js.map +1 -0
  108. package/dist/server/services/instances.d.ts +52 -0
  109. package/dist/server/services/instances.d.ts.map +1 -0
  110. package/dist/server/services/instances.js +241 -0
  111. package/dist/server/services/instances.js.map +1 -0
  112. package/dist/server/services/pathUtils.d.ts +47 -0
  113. package/dist/server/services/pathUtils.d.ts.map +1 -0
  114. package/dist/server/services/pathUtils.js +124 -0
  115. package/dist/server/services/pathUtils.js.map +1 -0
  116. package/dist/server/services/platform.d.ts +72 -0
  117. package/dist/server/services/platform.d.ts.map +1 -0
  118. package/dist/server/services/platform.js +368 -0
  119. package/dist/server/services/platform.js.map +1 -0
  120. package/dist/server/services/sentry.d.ts +5 -0
  121. package/dist/server/services/sentry.d.ts.map +1 -0
  122. package/dist/server/services/sentry.js +71 -0
  123. package/dist/server/services/sentry.js.map +1 -0
  124. package/dist/server/services/terminal/pty-manager.d.ts +149 -0
  125. package/dist/server/services/terminal/pty-manager.d.ts.map +1 -0
  126. package/dist/server/services/terminal/pty-manager.js +377 -0
  127. package/dist/server/services/terminal/pty-manager.js.map +1 -0
  128. package/dist/server/services/terminal/tmux-manager.d.ts +82 -0
  129. package/dist/server/services/terminal/tmux-manager.d.ts.map +1 -0
  130. package/dist/server/services/terminal/tmux-manager.js +352 -0
  131. package/dist/server/services/terminal/tmux-manager.js.map +1 -0
  132. package/dist/server/services/websocket/autocomplete.d.ts +50 -0
  133. package/dist/server/services/websocket/autocomplete.d.ts.map +1 -0
  134. package/dist/server/services/websocket/autocomplete.js +361 -0
  135. package/dist/server/services/websocket/autocomplete.js.map +1 -0
  136. package/dist/server/services/websocket/file-utils.d.ts +44 -0
  137. package/dist/server/services/websocket/file-utils.d.ts.map +1 -0
  138. package/dist/server/services/websocket/file-utils.js +272 -0
  139. package/dist/server/services/websocket/file-utils.js.map +1 -0
  140. package/dist/server/services/websocket/handler.d.ts +246 -0
  141. package/dist/server/services/websocket/handler.d.ts.map +1 -0
  142. package/dist/server/services/websocket/handler.js +1771 -0
  143. package/dist/server/services/websocket/handler.js.map +1 -0
  144. package/dist/server/services/websocket/index.d.ts +11 -0
  145. package/dist/server/services/websocket/index.d.ts.map +1 -0
  146. package/dist/server/services/websocket/index.js +14 -0
  147. package/dist/server/services/websocket/index.js.map +1 -0
  148. package/dist/server/services/websocket/types.d.ts +214 -0
  149. package/dist/server/services/websocket/types.d.ts.map +1 -0
  150. package/dist/server/services/websocket/types.js +4 -0
  151. package/dist/server/services/websocket/types.js.map +1 -0
  152. package/dist/server/utils/agent-manager.d.ts +69 -0
  153. package/dist/server/utils/agent-manager.d.ts.map +1 -0
  154. package/dist/server/utils/agent-manager.js +269 -0
  155. package/dist/server/utils/agent-manager.js.map +1 -0
  156. package/dist/server/utils/paths.d.ts +25 -0
  157. package/dist/server/utils/paths.d.ts.map +1 -0
  158. package/dist/server/utils/paths.js +38 -0
  159. package/dist/server/utils/paths.js.map +1 -0
  160. package/dist/server/utils/port-manager.d.ts +10 -0
  161. package/dist/server/utils/port-manager.d.ts.map +1 -0
  162. package/dist/server/utils/port-manager.js +60 -0
  163. package/dist/server/utils/port-manager.js.map +1 -0
  164. package/dist/server/utils/port.d.ts +26 -0
  165. package/dist/server/utils/port.d.ts.map +1 -0
  166. package/dist/server/utils/port.js +83 -0
  167. package/dist/server/utils/port.js.map +1 -0
  168. package/hooks/bouncer.sh +138 -0
  169. package/package.json +74 -0
  170. package/server/README.md +191 -0
  171. package/server/cli/headless/claude-invoker.ts +415 -0
  172. package/server/cli/headless/index.ts +39 -0
  173. package/server/cli/headless/mcp-config.ts +87 -0
  174. package/server/cli/headless/output-utils.ts +109 -0
  175. package/server/cli/headless/prompt-utils.ts +108 -0
  176. package/server/cli/headless/runner.ts +133 -0
  177. package/server/cli/headless/types.ts +118 -0
  178. package/server/cli/improvisation-session-manager.ts +531 -0
  179. package/server/index.ts +456 -0
  180. package/server/mcp/README.md +122 -0
  181. package/server/mcp/bouncer-cli.ts +127 -0
  182. package/server/mcp/bouncer-integration.ts +430 -0
  183. package/server/mcp/security-audit.ts +180 -0
  184. package/server/mcp/security-patterns.ts +290 -0
  185. package/server/mcp/server.ts +174 -0
  186. package/server/routes/files.ts +29 -0
  187. package/server/routes/improvise.ts +82 -0
  188. package/server/routes/index.ts +13 -0
  189. package/server/routes/instances.ts +54 -0
  190. package/server/routes/notifications.ts +158 -0
  191. package/server/services/analytics.ts +277 -0
  192. package/server/services/auth.ts +80 -0
  193. package/server/services/client-id.ts +68 -0
  194. package/server/services/credentials.ts +134 -0
  195. package/server/services/files.ts +710 -0
  196. package/server/services/instances.ts +275 -0
  197. package/server/services/pathUtils.ts +158 -0
  198. package/server/services/platform.test.ts +1314 -0
  199. package/server/services/platform.ts +435 -0
  200. package/server/services/sentry.ts +81 -0
  201. package/server/services/terminal/pty-manager.ts +464 -0
  202. package/server/services/terminal/tmux-manager.ts +426 -0
  203. package/server/services/websocket/autocomplete.ts +438 -0
  204. package/server/services/websocket/file-utils.ts +305 -0
  205. package/server/services/websocket/handler.test.ts +20 -0
  206. package/server/services/websocket/handler.ts +2047 -0
  207. package/server/services/websocket/index.ts +40 -0
  208. package/server/services/websocket/types.ts +339 -0
  209. package/server/tsconfig.json +19 -0
  210. package/server/utils/agent-manager.ts +323 -0
  211. package/server/utils/paths.ts +45 -0
  212. package/server/utils/port-manager.ts +70 -0
  213. package/server/utils/port.ts +102 -0
@@ -0,0 +1,247 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file for details.
3
+ /**
4
+ * Sensitive paths that require AI context review
5
+ * These aren't auto-denied - they need context analysis to determine intent
6
+ */
7
+ export const SENSITIVE_PATHS = [
8
+ // System directories - might be legitimate (e.g., user asked to configure something)
9
+ { pattern: /^(Write|Edit):\s*\/etc\//i, reason: 'System configuration - verify user intent' },
10
+ { pattern: /^(Write|Edit):\s*\/(bin|sbin|usr\/bin|usr\/sbin)\//i, reason: 'System binaries - verify user intent' },
11
+ { pattern: /^(Write|Edit):\s*\/boot\//i, reason: 'Boot directory - verify user intent' },
12
+ { pattern: /^(Write|Edit):\s*\/root\//i, reason: 'Root home - verify user intent' },
13
+ { pattern: /^(Write|Edit):\s*\/System\//i, reason: 'macOS system - verify user intent' },
14
+ { pattern: /^(Write|Edit):\s*\/Library\/(LaunchDaemons|LaunchAgents)\//i, reason: 'macOS launch services - verify user intent' },
15
+ // Credential/security files - high sensitivity, need clear user intent
16
+ { pattern: /^(Write|Edit):\s*.*\/\.ssh\//i, reason: 'SSH configuration - verify user intent' },
17
+ { pattern: /^(Write|Edit):\s*.*\/\.gnupg\//i, reason: 'GPG keys - verify user intent' },
18
+ { pattern: /^(Write|Edit):\s*.*\/\.aws\/(credentials|config)/i, reason: 'AWS credentials - verify user intent' },
19
+ { pattern: /^(Write|Edit):\s*.*\/(\.env|\.env\.local|\.env\.production)$/i, reason: 'Environment secrets - verify user intent' },
20
+ // Shell profiles - common legitimate edits but also attack vector
21
+ { pattern: /^(Write|Edit):\s*.*\/(\.bash_profile|\.bashrc|\.zshrc|\.profile|\.zprofile)$/i, reason: 'Shell profile - verify user intent' },
22
+ ];
23
+ /**
24
+ * Critical threats - auto-deny regardless of context
25
+ *
26
+ * These are NOT about "dangerous commands" but about commands that:
27
+ * 1. Are NEVER legitimate in any dev workflow
28
+ * 2. Have catastrophic, irreversible consequences
29
+ * 3. The cost of false positive (blocking) is negligible
30
+ *
31
+ * Note: Most "dangerous" commands (curl|bash, rm -rf, sudo) go to Haiku
32
+ * for context review. Only truly never-legitimate commands are here.
33
+ */
34
+ export const CRITICAL_THREATS = [
35
+ // Deleting root or home - no legitimate dev task requires this
36
+ // If user really wants this, they can run it manually outside Claude
37
+ {
38
+ pattern: /rm\s+-rf\s+(\/|~)($|\s)/i,
39
+ reason: 'Deleting root (/) or home (~) directory is never a legitimate dev task'
40
+ },
41
+ {
42
+ pattern: /:\(\)\{.*\}|:\(\)\{.*:\|:/i,
43
+ reason: 'Fork bomb detected - would cause system resource exhaustion'
44
+ },
45
+ {
46
+ pattern: /dd\s+if=\/dev\/zero\s+of=\/dev\/sd/i,
47
+ reason: 'Attempting to overwrite disk device - would destroy data'
48
+ },
49
+ {
50
+ pattern: /mkfs\./i,
51
+ reason: 'Attempting to format filesystem - would destroy all data'
52
+ },
53
+ {
54
+ pattern: /eval.*\$\(.*base64.*\)/i,
55
+ reason: 'Obfuscated code execution via base64 - common malware technique'
56
+ },
57
+ {
58
+ pattern: />\s*\/dev\/sd[a-z]/i,
59
+ reason: 'Direct write to disk device - would corrupt filesystem'
60
+ },
61
+ {
62
+ pattern: /chmod\s+000\s+\//i,
63
+ reason: 'Attempting to make system directories inaccessible'
64
+ }
65
+ // NOTE: curl|bash is NOT here - it goes to Haiku for context review
66
+ // The question is "did a bad actor inject this?" not "is curl|bash dangerous?"
67
+ ];
68
+ /**
69
+ * Safe operations that can be immediately allowed (confidence: 95%)
70
+ * These are read-only or obviously safe operations that don't need context review
71
+ */
72
+ export const SAFE_OPERATIONS = [
73
+ // Read operations are always safe - no side effects
74
+ { pattern: /^Read:/i },
75
+ { pattern: /^Glob:/i },
76
+ { pattern: /^Grep:/i },
77
+ // Write/Edit to user home directory or subdirectories - user requested, allow it
78
+ // Excludes system paths which go through critical threats check
79
+ { pattern: /^Write:\s*\/Users\/[^/]+\//i }, // macOS home dirs - Write
80
+ { pattern: /^Edit:\s*\/Users\/[^/]+\//i }, // macOS home dirs - Edit
81
+ { pattern: /^Write:\s*\/home\/[^/]+\//i }, // Linux home dirs - Write
82
+ { pattern: /^Edit:\s*\/home\/[^/]+\//i }, // Linux home dirs - Edit
83
+ // Safe bash commands - common development workflows
84
+ // NOTE: curl|bash goes to Haiku for context review, not auto-allowed
85
+ { pattern: /^Bash:\s*(npm|yarn|pnpm|bun)\s+(install|ci|run|test|build|dev|start|lint|format)($|\s)/i },
86
+ { pattern: /^Bash:\s*git\s+(status|log|diff|show|branch|clone|pull|fetch|add|stash|checkout)($|\s)/i },
87
+ { pattern: /^Bash:\s*docker\s+(build|run|ps|logs|compose|images)($|\s)/i },
88
+ { pattern: /^Bash:\s*(pytest|cargo\s+(build|test|run|check)|go\s+(build|test|run|mod))($|\s)/i },
89
+ { pattern: /^Bash:\s*(mkdir|cd|ls|pwd|cat|head|tail|wc|sort|uniq|grep|find|which|echo|env)($|\s)/i },
90
+ // Cleanup of build artifacts - always safe, commonly requested
91
+ { pattern: /^Bash:\s*rm\s+-rf\s+(\.\/)?node_modules($|\s)/i },
92
+ { pattern: /^Bash:\s*rm\s+-rf\s+(\.\/)?dist($|\s)/i },
93
+ { pattern: /^Bash:\s*rm\s+-rf\s+(\.\/)?build($|\s)/i },
94
+ { pattern: /^Bash:\s*rm\s+-rf\s+(\.\/)?\.cache($|\s)/i },
95
+ { pattern: /^Bash:\s*rm\s+-rf\s+(\.\/)?\.next($|\s)/i },
96
+ { pattern: /^Bash:\s*rm\s+-rf\s+(\.\/)?target($|\s)/i },
97
+ { pattern: /^Bash:\s*rm\s+-rf\s+(\.\/)?__pycache__($|\s)/i },
98
+ // Write/Edit to temp directories - ephemeral, low risk
99
+ { pattern: /^(Write|Edit):\s*\/tmp\//i },
100
+ { pattern: /^(Write|Edit):\s*\/var\/tmp\//i },
101
+ ];
102
+ /**
103
+ * Patterns that trigger AI context review
104
+ * These operations need context analysis to determine if they align with user intent
105
+ *
106
+ * The AI should consider:
107
+ * 1. Did the user explicitly request this operation?
108
+ * 2. Does it make sense given the task at hand?
109
+ * 3. Is the content/action appropriate for the target?
110
+ */
111
+ export const NEEDS_AI_REVIEW = [
112
+ // Remote code execution patterns
113
+ {
114
+ pattern: /(curl|wget).*\|.*(?:bash|sh)/i,
115
+ reason: 'Pipe to shell - verify source is trusted and user intended this'
116
+ },
117
+ // Elevated privileges
118
+ {
119
+ pattern: /sudo/i,
120
+ reason: 'Elevated privileges - verify user intended this action'
121
+ },
122
+ // Destructive operations (except safe build artifact cleanup)
123
+ {
124
+ pattern: /rm\s+-rf/i,
125
+ reason: 'Recursive deletion - verify target matches user intent'
126
+ },
127
+ // ALL Write/Edit operations that aren't to /tmp go through context review
128
+ // This is the key change: we review based on context, not blanket allow/deny
129
+ {
130
+ pattern: /^(Write|Edit):\s*(?!\/tmp\/|\/var\/tmp\/)/i,
131
+ reason: 'File modification - verify aligns with user request'
132
+ },
133
+ ];
134
+ /**
135
+ * Check if operation matches any pattern in array
136
+ */
137
+ export function matchesPattern(operation, patterns) {
138
+ for (const pattern of patterns) {
139
+ if (pattern.pattern.test(operation)) {
140
+ return pattern;
141
+ }
142
+ }
143
+ return null;
144
+ }
145
+ /**
146
+ * Determine if operation requires AI context review
147
+ *
148
+ * The philosophy here is:
149
+ * - SAFE_OPERATIONS: No review needed (read-only, temp files, build artifact cleanup)
150
+ * - CRITICAL_THREATS: Auto-deny, no review (catastrophic operations)
151
+ * - Everything else: AI reviews context to determine if it matches user intent
152
+ */
153
+ const SAFE_RM_PATTERNS = [
154
+ /rm\s+-rf\s+(\.\/)?node_modules($|\s)/i,
155
+ /rm\s+-rf\s+(\.\/)?dist($|\s)/i,
156
+ /rm\s+-rf\s+(\.\/)?build($|\s)/i,
157
+ /rm\s+-rf\s+(\.\/)?\.cache($|\s)/i,
158
+ /rm\s+-rf\s+(\.\/)?\.next($|\s)/i,
159
+ /rm\s+-rf\s+(\.\/)?target($|\s)/i,
160
+ /rm\s+-rf\s+(\.\/)?__pycache__($|\s)/i,
161
+ ];
162
+ export function requiresAIReview(operation) {
163
+ if (matchesPattern(operation, SAFE_OPERATIONS))
164
+ return false;
165
+ if (matchesPattern(operation, CRITICAL_THREATS))
166
+ return false;
167
+ if (matchesPattern(operation, NEEDS_AI_REVIEW)) {
168
+ return !SAFE_RM_PATTERNS.some(p => p.test(operation));
169
+ }
170
+ if (/\$\{.*\}|\$\(.*\)/.test(operation) || /\*\*?/.test(operation))
171
+ return true;
172
+ if (/^Bash:\s*\.\//.test(operation))
173
+ return true;
174
+ return false;
175
+ }
176
+ /**
177
+ * Check if operation targets a sensitive path
178
+ * Used to provide additional context to AI reviewer
179
+ */
180
+ export function isSensitivePath(operation) {
181
+ return matchesPattern(operation, SENSITIVE_PATHS);
182
+ }
183
+ /**
184
+ * Classify operation risk level for context-aware review
185
+ *
186
+ * Risk levels indicate how much scrutiny the AI should apply:
187
+ * - critical: Catastrophic if wrong (rm -rf /, fork bombs) - auto-deny
188
+ * - high: Needs clear user intent (sudo, sensitive paths, credentials)
189
+ * - medium: Normal file operations - verify matches user request
190
+ * - low: Safe operations - minimal review needed
191
+ */
192
+ export function classifyRisk(operation) {
193
+ // Critical threats are auto-denied
194
+ const criticalThreat = matchesPattern(operation, CRITICAL_THREATS);
195
+ if (criticalThreat) {
196
+ return {
197
+ isDestructive: true,
198
+ riskLevel: 'critical',
199
+ reasons: [criticalThreat.reason || 'Critical threat detected']
200
+ };
201
+ }
202
+ // Sensitive paths need high scrutiny but aren't auto-denied
203
+ const sensitivePath = matchesPattern(operation, SENSITIVE_PATHS);
204
+ if (sensitivePath) {
205
+ return {
206
+ isDestructive: false, // Not inherently destructive, just sensitive
207
+ riskLevel: 'high',
208
+ reasons: [sensitivePath.reason || 'Sensitive path - requires clear user intent']
209
+ };
210
+ }
211
+ // Other patterns that need elevated review
212
+ const elevatedPatterns = [
213
+ { pattern: /sudo/i, reason: 'Elevated privileges requested' },
214
+ { pattern: /DROP\s+(TABLE|DATABASE)/i, reason: 'Database deletion' },
215
+ { pattern: /chmod\s+777/i, reason: 'Dangerous permissions' },
216
+ { pattern: /(curl|wget).*\|.*(bash|sh)/i, reason: 'Remote code execution' },
217
+ { pattern: /pkill|killall/i, reason: 'Process termination' },
218
+ ];
219
+ for (const pattern of elevatedPatterns) {
220
+ if (pattern.pattern.test(operation)) {
221
+ return {
222
+ isDestructive: true,
223
+ riskLevel: 'high',
224
+ reasons: [pattern.reason || 'Elevated risk operation']
225
+ };
226
+ }
227
+ }
228
+ // Medium risk: only recursive deletions outside safe dirs
229
+ // NOTE: Write/Edit are NOT flagged as risky - they're normal dev operations
230
+ if (/rm\s+-rf/i.test(operation)) {
231
+ // Check if it's actually safe (build artifacts, temp)
232
+ if (matchesPattern(operation, SAFE_OPERATIONS)) {
233
+ return { isDestructive: false, riskLevel: 'low', reasons: [] };
234
+ }
235
+ return {
236
+ isDestructive: true,
237
+ riskLevel: 'medium',
238
+ reasons: ['Recursive deletion']
239
+ };
240
+ }
241
+ return {
242
+ isDestructive: false,
243
+ riskLevel: 'low',
244
+ reasons: []
245
+ };
246
+ }
247
+ //# sourceMappingURL=security-patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-patterns.js","sourceRoot":"","sources":["../../../server/mcp/security-patterns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env -S npx tsx
2
+ export {};
3
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../server/mcp/server.ts"],"names":[],"mappings":""}
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env -S npx tsx
2
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
3
+ // Licensed under the MIT License. See LICENSE file for details.
4
+ /**
5
+ * MCP Bouncer Server
6
+ *
7
+ * Provides permission approval/denial for Claude Code tool use via MCP protocol.
8
+ * Integrates with Mstro's existing bouncer-integration.ts for security analysis.
9
+ *
10
+ * Usage:
11
+ * claude --print --permission-prompt-tool mcp__mstro-bouncer__approval_prompt \
12
+ * --mcp-config mstro-bouncer-mcp.json \
13
+ * "your prompt here"
14
+ */
15
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
16
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
17
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
18
+ import { reviewOperation } from './bouncer-integration.js';
19
+ // Create MCP server
20
+ const server = new Server({
21
+ name: 'mstro-bouncer',
22
+ version: '1.0.0',
23
+ }, {
24
+ capabilities: {
25
+ tools: {},
26
+ },
27
+ });
28
+ /**
29
+ * List available tools (required by MCP protocol)
30
+ */
31
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
32
+ return {
33
+ tools: [
34
+ {
35
+ name: 'approval_prompt',
36
+ description: 'Analyze and approve/deny tool use requests from Claude Code. Integrates with Mstro security bouncer for AI-powered risk analysis.',
37
+ inputSchema: {
38
+ type: 'object',
39
+ properties: {
40
+ tool_name: {
41
+ type: 'string',
42
+ description: 'Name of the tool being requested (e.g., "Bash", "Write", "Read")',
43
+ },
44
+ input: {
45
+ type: 'object',
46
+ description: 'Tool input parameters as JSON object',
47
+ },
48
+ },
49
+ required: ['tool_name', 'input'],
50
+ },
51
+ },
52
+ ],
53
+ };
54
+ });
55
+ /**
56
+ * Handle tool calls (approval_prompt)
57
+ */
58
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
59
+ if (request.params.name !== 'approval_prompt') {
60
+ throw new Error(`Unknown tool: ${request.params.name}`);
61
+ }
62
+ const { tool_name, input } = request.params.arguments;
63
+ console.error(`[MCP Bouncer] Analyzing ${tool_name} request...`);
64
+ // Format operation string for bouncer analysis
65
+ // Example: "Bash: rm -rf node_modules"
66
+ let operationString = `${tool_name}:`;
67
+ // Extract file path with multiple property name support
68
+ // Claude Code may use file_path, filePath, or path depending on context
69
+ const getFilePath = (inp) => inp.file_path || inp.filePath || inp.path;
70
+ if (tool_name === 'Bash' && input.command) {
71
+ operationString += ` ${input.command}`;
72
+ }
73
+ else if (['Write', 'Edit', 'Read'].includes(tool_name)) {
74
+ const filePath = getFilePath(input);
75
+ operationString += filePath ? ` ${filePath}` : ` ${JSON.stringify(input)}`;
76
+ }
77
+ else {
78
+ // Generic format: include all input parameters
79
+ operationString += ` ${JSON.stringify(input)}`;
80
+ }
81
+ // Build bouncer request with context
82
+ const bouncerRequest = {
83
+ operation: operationString,
84
+ context: {
85
+ purpose: `Tool use request from Claude`,
86
+ workingDirectory: process.cwd(),
87
+ toolName: tool_name,
88
+ toolInput: input,
89
+ },
90
+ };
91
+ try {
92
+ // Use existing Mstro bouncer for analysis
93
+ const decision = await reviewOperation(bouncerRequest);
94
+ console.error(`[MCP Bouncer] Decision: ${decision.decision} (${decision.confidence}% confidence)`);
95
+ console.error(`[MCP Bouncer] Reasoning: ${decision.reasoning}`);
96
+ // Format response for Claude Code
97
+ const response = decision.decision === 'deny'
98
+ ? {
99
+ behavior: 'deny',
100
+ message: `🚫 ${decision.reasoning}${decision.alternative ? `\n\nAlternative: ${decision.alternative}` : ''}`,
101
+ }
102
+ : {
103
+ behavior: 'allow',
104
+ updatedInput: input,
105
+ message: decision.decision === 'warn_allow'
106
+ ? `⚠️ Allowed with caution: ${decision.reasoning}`
107
+ : undefined,
108
+ };
109
+ return {
110
+ content: [
111
+ {
112
+ type: 'text',
113
+ text: JSON.stringify(response),
114
+ },
115
+ ],
116
+ };
117
+ }
118
+ catch (error) {
119
+ console.error(`[MCP Bouncer] Error: ${error.message}`);
120
+ // Fail-safe: deny on error
121
+ return {
122
+ content: [
123
+ {
124
+ type: 'text',
125
+ text: JSON.stringify({
126
+ behavior: 'deny',
127
+ message: `Security analysis failed: ${error.message}. Denying for safety.`,
128
+ }),
129
+ },
130
+ ],
131
+ };
132
+ }
133
+ });
134
+ /**
135
+ * Start the MCP server
136
+ */
137
+ async function main() {
138
+ const transport = new StdioServerTransport();
139
+ await server.connect(transport);
140
+ console.error('[MCP Bouncer] Server started and ready');
141
+ }
142
+ main().catch((error) => {
143
+ console.error('[MCP Bouncer] Fatal error:', error);
144
+ process.exit(1);
145
+ });
146
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../server/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * File Routes
3
+ *
4
+ * Handles file listing and autocomplete.
5
+ */
6
+ import { Hono } from 'hono';
7
+ import type { FileService } from '../services/files.js';
8
+ export declare function createFileRoutes(fileService: FileService): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
9
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../server/routes/files.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAEvD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,8EAgBxD"}
@@ -0,0 +1,24 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file for details.
3
+ /**
4
+ * File Routes
5
+ *
6
+ * Handles file listing and autocomplete.
7
+ */
8
+ import { Hono } from 'hono';
9
+ export function createFileRoutes(fileService) {
10
+ const routes = new Hono();
11
+ routes.get('/', (c) => {
12
+ try {
13
+ const filter = c.req.query('filter') || '';
14
+ const baseDir = (c.req.query('baseDir') || 'scores');
15
+ const files = fileService.getAllFiles(baseDir, filter);
16
+ return c.json({ files });
17
+ }
18
+ catch (error) {
19
+ return c.json({ error: error.message }, 500);
20
+ }
21
+ });
22
+ return routes;
23
+ }
24
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../../server/routes/files.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,gEAAgE;AAEhE;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAG3B,MAAM,UAAU,gBAAgB,CAAC,WAAwB;IACvD,MAAM,MAAM,GAAG,IAAI,IAAI,EAAE,CAAA;IAEzB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE;QACpB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAA;YAC1C,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAyB,CAAA;YAE5E,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;YACtD,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;QAC1B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAA;QACzD,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Hono } from 'hono';
2
+ export declare function createImproviseRoutes(workingDir: string): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ //# sourceMappingURL=improvise.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"improvise.d.ts","sourceRoot":"","sources":["../../../server/routes/improvise.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,8EAqEvD"}
@@ -0,0 +1,72 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file for details.
3
+ /**
4
+ * Improvise History Routes
5
+ *
6
+ * Handles improvise session history retrieval.
7
+ */
8
+ import { join } from 'node:path';
9
+ import { Hono } from 'hono';
10
+ export function createImproviseRoutes(workingDir) {
11
+ const routes = new Hono();
12
+ routes.get('/sessions', async (c) => {
13
+ try {
14
+ const sessionsDir = join(workingDir, '.mstro', 'improvise');
15
+ const { readdirSync, existsSync, readFileSync } = await import('node:fs');
16
+ if (!existsSync(sessionsDir)) {
17
+ return c.json({ sessions: [] });
18
+ }
19
+ // Look for history-*.json files in the improvise directory
20
+ const historyFiles = readdirSync(sessionsDir)
21
+ .filter((name) => name.startsWith('history-') && name.endsWith('.json'))
22
+ .sort((a, b) => {
23
+ // Sort by timestamp in filename (newer first)
24
+ const timestampA = parseInt(a.replace('history-', '').replace('.json', ''), 10);
25
+ const timestampB = parseInt(b.replace('history-', '').replace('.json', ''), 10);
26
+ return timestampB - timestampA;
27
+ });
28
+ const sessions = historyFiles.map((filename) => {
29
+ const historyPath = join(sessionsDir, filename);
30
+ try {
31
+ const historyData = JSON.parse(readFileSync(historyPath, 'utf-8'));
32
+ const firstPrompt = historyData.movements?.[0]?.userPrompt || '';
33
+ return {
34
+ sessionId: historyData.sessionId,
35
+ startedAt: historyData.startedAt,
36
+ lastActivityAt: historyData.lastActivityAt,
37
+ totalTokens: historyData.totalTokens,
38
+ movementCount: historyData.movements?.length || 0,
39
+ title: firstPrompt.slice(0, 80) + (firstPrompt.length > 80 ? '...' : ''),
40
+ movements: historyData.movements || []
41
+ };
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }).filter(Boolean);
47
+ return c.json({ sessions });
48
+ }
49
+ catch (error) {
50
+ return c.json({ error: error.message }, 500);
51
+ }
52
+ });
53
+ routes.get('/sessions/:sessionId', async (c) => {
54
+ try {
55
+ const { sessionId } = c.req.param();
56
+ // Extract timestamp from sessionId (e.g., "improv-1234567890" -> "1234567890")
57
+ const timestamp = sessionId.replace('improv-', '');
58
+ const historyPath = join(workingDir, '.mstro', 'improvise', `history-${timestamp}.json`);
59
+ const { existsSync, readFileSync } = await import('node:fs');
60
+ if (!existsSync(historyPath)) {
61
+ return c.json({ error: 'Session not found' }, 404);
62
+ }
63
+ const historyData = JSON.parse(readFileSync(historyPath, 'utf-8'));
64
+ return c.json(historyData);
65
+ }
66
+ catch (error) {
67
+ return c.json({ error: error.message }, 500);
68
+ }
69
+ });
70
+ return routes;
71
+ }
72
+ //# sourceMappingURL=improvise.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"improvise.js","sourceRoot":"","sources":["../../../server/routes/improvise.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Routes Index
3
+ *
4
+ * Re-exports all route creators for easy importing.
5
+ */
6
+ export { createFileRoutes } from './files.js';
7
+ export { createImproviseRoutes } from './improvise.js';
8
+ export { createInstanceRoutes, createShutdownRoute } from './instances.js';
9
+ export { createNotificationRoutes } from './notifications.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../server/routes/index.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAC1E,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1,12 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file for details.
3
+ /**
4
+ * Routes Index
5
+ *
6
+ * Re-exports all route creators for easy importing.
7
+ */
8
+ export { createFileRoutes } from './files.js';
9
+ export { createImproviseRoutes } from './improvise.js';
10
+ export { createInstanceRoutes, createShutdownRoute } from './instances.js';
11
+ export { createNotificationRoutes } from './notifications.js';
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/routes/index.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,gEAAgE;AAEhE;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAC1E,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Instance Management Routes
3
+ *
4
+ * Handles server instance discovery and management.
5
+ */
6
+ import { Hono } from 'hono';
7
+ import { InstanceRegistry } from '../services/instances.js';
8
+ export declare function createInstanceRoutes(instanceRegistry: InstanceRegistry): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
9
+ export declare function createShutdownRoute(instanceRegistry: InstanceRegistry): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
10
+ //# sourceMappingURL=instances.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instances.d.ts","sourceRoot":"","sources":["../../../server/routes/instances.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAE3D,wBAAgB,oBAAoB,CAAC,gBAAgB,EAAE,gBAAgB,8EAyBtE;AAED,wBAAgB,mBAAmB,CAAC,gBAAgB,EAAE,gBAAgB,8EAarE"}
@@ -0,0 +1,47 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file for details.
3
+ /**
4
+ * Instance Management Routes
5
+ *
6
+ * Handles server instance discovery and management.
7
+ */
8
+ import { Hono } from 'hono';
9
+ import { getClientId } from '../services/client-id.js';
10
+ import { InstanceRegistry } from '../services/instances.js';
11
+ export function createInstanceRoutes(instanceRegistry) {
12
+ const routes = new Hono();
13
+ routes.get('/', (c) => {
14
+ try {
15
+ const instances = InstanceRegistry.getAllInstances();
16
+ return c.json({ instances });
17
+ }
18
+ catch (error) {
19
+ return c.json({ error: error.message }, 500);
20
+ }
21
+ });
22
+ routes.get('/current', (c) => {
23
+ try {
24
+ const instance = instanceRegistry.getCurrentInstance();
25
+ return c.json({
26
+ instance,
27
+ clientId: getClientId()
28
+ });
29
+ }
30
+ catch (error) {
31
+ return c.json({ error: error.message }, 500);
32
+ }
33
+ });
34
+ return routes;
35
+ }
36
+ export function createShutdownRoute(instanceRegistry) {
37
+ const routes = new Hono();
38
+ routes.post('/', (c) => {
39
+ setTimeout(() => {
40
+ instanceRegistry.unregister();
41
+ process.exit(0);
42
+ }, 100);
43
+ return c.json({ success: true, message: 'Shutting down...' });
44
+ });
45
+ return routes;
46
+ }
47
+ //# sourceMappingURL=instances.js.map