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 @@
1
+ {"version":3,"file":"instances.js","sourceRoot":"","sources":["../../../server/routes/instances.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,gEAAgE;AAEhE;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAE3D,MAAM,UAAU,oBAAoB,CAAC,gBAAkC;IACrE,MAAM,MAAM,GAAG,IAAI,IAAI,EAAE,CAAA;IAEzB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE;QACpB,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,gBAAgB,CAAC,eAAe,EAAE,CAAA;YACpD,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,CAAA;QAC9B,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,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE;QAC3B,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,gBAAgB,CAAC,kBAAkB,EAAE,CAAA;YACtD,OAAO,CAAC,CAAC,IAAI,CAAC;gBACZ,QAAQ;gBACR,QAAQ,EAAE,WAAW,EAAE;aACxB,CAAC,CAAA;QACJ,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;AAED,MAAM,UAAU,mBAAmB,CAAC,gBAAkC;IACpE,MAAM,MAAM,GAAG,IAAI,IAAI,EAAE,CAAA;IAEzB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE;QACrB,UAAU,CAAC,GAAG,EAAE;YACd,gBAAgB,CAAC,UAAU,EAAE,CAAA;YAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC,EAAE,GAAG,CAAC,CAAA;QAEP,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC,CAAA;IAC/D,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Hono } from 'hono';
2
+ export declare function createNotificationRoutes(workingDir: string): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ //# sourceMappingURL=notifications.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../../../server/routes/notifications.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,8EA4B1D"}
@@ -0,0 +1,136 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file for details.
3
+ /**
4
+ * Notification Routes
5
+ *
6
+ * Handles notification-related operations including AI-powered summary generation.
7
+ */
8
+ import { spawn } from 'node:child_process';
9
+ import { existsSync, mkdirSync, unlinkSync, writeFileSync } from 'node:fs';
10
+ import { join } from 'node:path';
11
+ import { Hono } from 'hono';
12
+ export function createNotificationRoutes(workingDir) {
13
+ const routes = new Hono();
14
+ /**
15
+ * Generate a summary for browser notification using Claude Haiku
16
+ * POST /summarize
17
+ * Body: { prompt: string, output: string }
18
+ * Returns: { summary: string }
19
+ */
20
+ routes.post('/summarize', async (c) => {
21
+ try {
22
+ const body = await c.req.json();
23
+ const { prompt, output } = body;
24
+ if (!prompt || !output) {
25
+ return c.json({ error: 'Missing required fields: prompt and output' }, 400);
26
+ }
27
+ const summary = await generateNotificationSummary(prompt, output, workingDir);
28
+ return c.json({ summary });
29
+ }
30
+ catch (error) {
31
+ console.error('[Notifications] Error generating summary:', error);
32
+ // Return a fallback summary on error
33
+ return c.json({ summary: 'Task completed' });
34
+ }
35
+ });
36
+ return routes;
37
+ }
38
+ /**
39
+ * Generate a notification summary using Claude Haiku
40
+ */
41
+ async function generateNotificationSummary(userPrompt, output, workingDir) {
42
+ return new Promise((resolve) => {
43
+ // Create temp directory if it doesn't exist
44
+ const tempDir = join(workingDir, '.mstro', 'tmp');
45
+ if (!existsSync(tempDir)) {
46
+ mkdirSync(tempDir, { recursive: true });
47
+ }
48
+ // Truncate output if too long (keep first and last parts for context)
49
+ let truncatedOutput = output;
50
+ if (output.length > 4000) {
51
+ const firstPart = output.slice(0, 2000);
52
+ const lastPart = output.slice(-1500);
53
+ truncatedOutput = `${firstPart}\n\n... [output truncated] ...\n\n${lastPart}`;
54
+ }
55
+ // Build the prompt for summary generation
56
+ const summaryPrompt = `You are generating a SHORT browser notification summary for a completed task.
57
+ The user ran a task and wants a brief notification to remind them what happened.
58
+
59
+ USER'S ORIGINAL PROMPT:
60
+ "${userPrompt}"
61
+
62
+ TASK OUTPUT (may be truncated):
63
+ ${truncatedOutput}
64
+
65
+ Generate a notification summary following these rules:
66
+ 1. Maximum 100 characters (this is a browser notification)
67
+ 2. Focus on the OUTCOME, not the process
68
+ 3. Be specific about what was accomplished
69
+ 4. Use past tense (e.g., "Fixed bug in auth.ts", "Added 3 new tests")
70
+ 5. If there was an error, mention it briefly
71
+ 6. No emojis, no markdown, just plain text
72
+
73
+ Respond with ONLY the summary text, nothing else.`;
74
+ // Write prompt to temp file
75
+ const promptFile = join(tempDir, `notif-summary-${Date.now()}.txt`);
76
+ writeFileSync(promptFile, summaryPrompt);
77
+ const systemPrompt = 'You are a notification summary assistant. Respond with only the summary text, no preamble or explanation.';
78
+ const args = [
79
+ '--print',
80
+ '--model', 'haiku',
81
+ '--system-prompt', systemPrompt,
82
+ promptFile
83
+ ];
84
+ const claude = spawn('claude', args, {
85
+ cwd: workingDir,
86
+ stdio: ['ignore', 'pipe', 'pipe']
87
+ });
88
+ let stdout = '';
89
+ let stderr = '';
90
+ claude.stdout?.on('data', (data) => {
91
+ stdout += data.toString();
92
+ });
93
+ claude.stderr?.on('data', (data) => {
94
+ stderr += data.toString();
95
+ });
96
+ claude.on('close', (code) => {
97
+ // Clean up temp file
98
+ try {
99
+ unlinkSync(promptFile);
100
+ }
101
+ catch {
102
+ // Ignore cleanup errors
103
+ }
104
+ if (code === 0 && stdout.trim()) {
105
+ // Truncate if somehow still too long
106
+ const summary = stdout.trim().slice(0, 150);
107
+ resolve(summary);
108
+ }
109
+ else {
110
+ console.error('[Notifications] Claude error:', stderr || 'Unknown error');
111
+ // Fallback to basic summary
112
+ resolve(createFallbackSummary(userPrompt));
113
+ }
114
+ });
115
+ claude.on('error', (err) => {
116
+ console.error('[Notifications] Failed to spawn Claude:', err);
117
+ resolve(createFallbackSummary(userPrompt));
118
+ });
119
+ // Timeout after 10 seconds
120
+ setTimeout(() => {
121
+ claude.kill();
122
+ resolve(createFallbackSummary(userPrompt));
123
+ }, 10000);
124
+ });
125
+ }
126
+ /**
127
+ * Create a fallback summary when AI summarization fails
128
+ */
129
+ function createFallbackSummary(userPrompt) {
130
+ const truncated = userPrompt.slice(0, 60);
131
+ if (userPrompt.length > 60) {
132
+ return `Completed: "${truncated}..."`;
133
+ }
134
+ return `Completed: "${truncated}"`;
135
+ }
136
+ //# sourceMappingURL=notifications.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../../server/routes/notifications.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Initialize PostHog client
3
+ * Call this once at server startup
4
+ */
5
+ export declare function initAnalytics(): Promise<void>;
6
+ /**
7
+ * Shutdown PostHog client gracefully
8
+ * Call this before process exit
9
+ */
10
+ export declare function shutdownAnalytics(): Promise<void>;
11
+ /**
12
+ * Track a custom event
13
+ */
14
+ export declare function trackEvent(event: string, properties?: Record<string, any>): void;
15
+ /**
16
+ * Identify a user (call after login)
17
+ */
18
+ export declare function identifyUser(userId: string, properties?: Record<string, any>): void;
19
+ /**
20
+ * Set telemetry preference in config file
21
+ */
22
+ export declare function setTelemetryEnabled(enabled: boolean): void;
23
+ /**
24
+ * Get current telemetry status
25
+ */
26
+ export declare function getTelemetryStatus(): {
27
+ enabled: boolean;
28
+ reason: string;
29
+ };
30
+ export declare const AnalyticsEvents: {
31
+ readonly CLI_STARTED: "cli_started";
32
+ readonly CLI_COMMAND: "cli_command";
33
+ readonly CLI_LOGIN: "cli_login";
34
+ readonly CLI_LOGOUT: "cli_logout";
35
+ readonly CLI_ERROR: "cli_error";
36
+ readonly SERVER_STARTED: "server_started";
37
+ readonly SERVER_STOPPED: "server_stopped";
38
+ readonly PLATFORM_CONNECTED: "platform_connected";
39
+ readonly PLATFORM_DISCONNECTED: "platform_disconnected";
40
+ readonly WEB_CLIENT_CONNECTED: "web_client_connected";
41
+ readonly WEB_CLIENT_DISCONNECTED: "web_client_disconnected";
42
+ readonly IMPROVISE_SESSION_STARTED: "improvise_session_started";
43
+ readonly IMPROVISE_PROMPT_RECEIVED: "improvise_prompt_received";
44
+ readonly IMPROVISE_MOVEMENT_STARTED: "improvise_movement_started";
45
+ readonly IMPROVISE_MOVEMENT_COMPLETED: "improvise_movement_completed";
46
+ readonly IMPROVISE_MOVEMENT_ERROR: "improvise_movement_error";
47
+ readonly IMPROVISE_SESSION_ENDED: "improvise_session_ended";
48
+ readonly IMPROVISE_ABORTED: "improvise_aborted";
49
+ readonly TERMINAL_SESSION_CREATED: "terminal_session_created";
50
+ readonly TERMINAL_SESSION_CLOSED: "terminal_session_closed";
51
+ readonly BOUNCER_TOOL_ALLOWED: "bouncer_tool_allowed";
52
+ readonly BOUNCER_TOOL_DENIED: "bouncer_tool_denied";
53
+ readonly BOUNCER_HAIKU_REVIEW: "bouncer_haiku_review";
54
+ };
55
+ export type AnalyticsEvent = typeof AnalyticsEvents[keyof typeof AnalyticsEvents];
56
+ //# sourceMappingURL=analytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../../server/services/analytics.ts"],"names":[],"mappings":"AA6FA;;;GAGG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAmBnD;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAKvD;AAuBD;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAWhF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAgBnF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgB1D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAsBzE;AAMD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;CAmClB,CAAA;AAEV,MAAM,MAAM,cAAc,GAAG,OAAO,eAAe,CAAC,MAAM,OAAO,eAAe,CAAC,CAAA"}
@@ -0,0 +1,240 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file for details.
3
+ /**
4
+ * PostHog Analytics Service for mstro CLI
5
+ *
6
+ * Provides analytics tracking for the mstro client.
7
+ * Uses PostHog Node SDK for server-side event tracking.
8
+ *
9
+ * Config is fetched from platform server (not hardcoded) so the
10
+ * PostHog key isn't exposed in the npm package.
11
+ *
12
+ * Telemetry is opt-out by default. Users can disable with:
13
+ * - Command: mstro telemetry off
14
+ * - Environment variable: MSTRO_TELEMETRY=0
15
+ */
16
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
17
+ import { arch, homedir, platform } from 'node:os';
18
+ import { join } from 'node:path';
19
+ import { PostHog } from 'posthog-node';
20
+ import { getClientId } from './client-id.js';
21
+ const MSTRO_DIR = join(homedir(), '.mstro');
22
+ const CONFIG_FILE = join(MSTRO_DIR, 'config.json');
23
+ const PLATFORM_URL = process.env.PLATFORM_URL || 'https://api.mstro.app';
24
+ let client = null;
25
+ let telemetryEnabled = null;
26
+ let analyticsConfig = null;
27
+ /**
28
+ * Check if telemetry is enabled
29
+ */
30
+ function isTelemetryEnabled() {
31
+ if (telemetryEnabled !== null) {
32
+ return telemetryEnabled;
33
+ }
34
+ // Check environment variable first
35
+ const envValue = process.env.MSTRO_TELEMETRY;
36
+ if (envValue === '0' || envValue === 'false') {
37
+ telemetryEnabled = false;
38
+ return false;
39
+ }
40
+ // Check config file
41
+ if (existsSync(CONFIG_FILE)) {
42
+ try {
43
+ const config = JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'));
44
+ if (config.telemetry === false) {
45
+ telemetryEnabled = false;
46
+ return false;
47
+ }
48
+ }
49
+ catch {
50
+ // Ignore parse errors
51
+ }
52
+ }
53
+ telemetryEnabled = true;
54
+ return true;
55
+ }
56
+ /**
57
+ * Fetch analytics config from platform server
58
+ * This keeps the PostHog key out of the npm package
59
+ */
60
+ async function fetchAnalyticsConfig() {
61
+ try {
62
+ const response = await fetch(`${PLATFORM_URL}/api/config/client`, {
63
+ method: 'GET',
64
+ headers: { 'Content-Type': 'application/json' },
65
+ });
66
+ if (!response.ok) {
67
+ return null;
68
+ }
69
+ const data = await response.json();
70
+ return {
71
+ posthogKey: data.analytics?.posthogKey || '',
72
+ posthogHost: data.analytics?.posthogHost || 'https://eu.i.posthog.com',
73
+ };
74
+ }
75
+ catch {
76
+ // Network error, platform unavailable - silently disable analytics
77
+ return null;
78
+ }
79
+ }
80
+ /**
81
+ * Initialize PostHog client
82
+ * Call this once at server startup
83
+ */
84
+ export async function initAnalytics() {
85
+ if (!isTelemetryEnabled()) {
86
+ return;
87
+ }
88
+ // Fetch config from platform
89
+ analyticsConfig = await fetchAnalyticsConfig();
90
+ if (!analyticsConfig?.posthogKey) {
91
+ // No key configured on platform, analytics disabled
92
+ return;
93
+ }
94
+ client = new PostHog(analyticsConfig.posthogKey, {
95
+ host: analyticsConfig.posthogHost,
96
+ // Flush events every 10 seconds or 20 events
97
+ flushAt: 20,
98
+ flushInterval: 10000,
99
+ });
100
+ }
101
+ /**
102
+ * Shutdown PostHog client gracefully
103
+ * Call this before process exit
104
+ */
105
+ export async function shutdownAnalytics() {
106
+ if (client) {
107
+ await client.shutdown();
108
+ client = null;
109
+ }
110
+ }
111
+ /**
112
+ * Get the distinct ID for this client
113
+ * Uses the persistent client ID from ~/.mstro/client-id
114
+ */
115
+ function getDistinctId() {
116
+ return getClientId();
117
+ }
118
+ /**
119
+ * Get common properties included with all events
120
+ */
121
+ function getCommonProperties() {
122
+ return {
123
+ os: platform(),
124
+ arch: arch(),
125
+ node_version: process.version,
126
+ mstro_version: process.env.npm_package_version || 'unknown',
127
+ source: 'client',
128
+ };
129
+ }
130
+ /**
131
+ * Track a custom event
132
+ */
133
+ export function trackEvent(event, properties) {
134
+ if (!client || !isTelemetryEnabled())
135
+ return;
136
+ client.capture({
137
+ distinctId: getDistinctId(),
138
+ event,
139
+ properties: {
140
+ ...getCommonProperties(),
141
+ ...properties,
142
+ },
143
+ });
144
+ }
145
+ /**
146
+ * Identify a user (call after login)
147
+ */
148
+ export function identifyUser(userId, properties) {
149
+ if (!client || !isTelemetryEnabled())
150
+ return;
151
+ // Link the client ID to the user ID
152
+ client.alias({
153
+ distinctId: userId,
154
+ alias: getDistinctId(),
155
+ });
156
+ client.identify({
157
+ distinctId: userId,
158
+ properties: {
159
+ ...getCommonProperties(),
160
+ ...properties,
161
+ },
162
+ });
163
+ }
164
+ /**
165
+ * Set telemetry preference in config file
166
+ */
167
+ export function setTelemetryEnabled(enabled) {
168
+ let config = {};
169
+ if (existsSync(CONFIG_FILE)) {
170
+ try {
171
+ config = JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'));
172
+ }
173
+ catch {
174
+ // Start fresh if parse fails
175
+ }
176
+ }
177
+ config.telemetry = enabled;
178
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
179
+ // Update cached value
180
+ telemetryEnabled = enabled;
181
+ }
182
+ /**
183
+ * Get current telemetry status
184
+ */
185
+ export function getTelemetryStatus() {
186
+ const envValue = process.env.MSTRO_TELEMETRY;
187
+ if (envValue === '0' || envValue === 'false') {
188
+ return { enabled: false, reason: 'Disabled via MSTRO_TELEMETRY environment variable' };
189
+ }
190
+ if (existsSync(CONFIG_FILE)) {
191
+ try {
192
+ const config = JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'));
193
+ if (config.telemetry === false) {
194
+ return { enabled: false, reason: 'Disabled via ~/.mstro/config.json' };
195
+ }
196
+ }
197
+ catch {
198
+ // Ignore
199
+ }
200
+ }
201
+ if (!analyticsConfig?.posthogKey) {
202
+ return { enabled: false, reason: 'Analytics not configured on platform' };
203
+ }
204
+ return { enabled: true, reason: 'Enabled (opt-out with MSTRO_TELEMETRY=0)' };
205
+ }
206
+ // ===========================================
207
+ // Event Constants - Use these for consistency
208
+ // ===========================================
209
+ export const AnalyticsEvents = {
210
+ // CLI events
211
+ CLI_STARTED: 'cli_started',
212
+ CLI_COMMAND: 'cli_command',
213
+ CLI_LOGIN: 'cli_login',
214
+ CLI_LOGOUT: 'cli_logout',
215
+ CLI_ERROR: 'cli_error',
216
+ // Server events
217
+ SERVER_STARTED: 'server_started',
218
+ SERVER_STOPPED: 'server_stopped',
219
+ // Connection events
220
+ PLATFORM_CONNECTED: 'platform_connected',
221
+ PLATFORM_DISCONNECTED: 'platform_disconnected',
222
+ WEB_CLIENT_CONNECTED: 'web_client_connected',
223
+ WEB_CLIENT_DISCONNECTED: 'web_client_disconnected',
224
+ // Improvise events
225
+ IMPROVISE_SESSION_STARTED: 'improvise_session_started',
226
+ IMPROVISE_PROMPT_RECEIVED: 'improvise_prompt_received',
227
+ IMPROVISE_MOVEMENT_STARTED: 'improvise_movement_started',
228
+ IMPROVISE_MOVEMENT_COMPLETED: 'improvise_movement_completed',
229
+ IMPROVISE_MOVEMENT_ERROR: 'improvise_movement_error',
230
+ IMPROVISE_SESSION_ENDED: 'improvise_session_ended',
231
+ IMPROVISE_ABORTED: 'improvise_aborted',
232
+ // Terminal events
233
+ TERMINAL_SESSION_CREATED: 'terminal_session_created',
234
+ TERMINAL_SESSION_CLOSED: 'terminal_session_closed',
235
+ // MCP/Bouncer events
236
+ BOUNCER_TOOL_ALLOWED: 'bouncer_tool_allowed',
237
+ BOUNCER_TOOL_DENIED: 'bouncer_tool_denied',
238
+ BOUNCER_HAIKU_REVIEW: 'bouncer_haiku_review',
239
+ };
240
+ //# sourceMappingURL=analytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../../server/services/analytics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export declare class AuthService {
2
+ private localToken;
3
+ constructor();
4
+ /**
5
+ * Load existing session token from disk, or create one if missing.
6
+ * This ensures all mstro instances on the same machine share the same token.
7
+ */
8
+ private loadOrCreateToken;
9
+ /**
10
+ * Write session token to ~/.mstro/session-token
11
+ */
12
+ private writeToken;
13
+ /**
14
+ * Validate the local session token (used for localhost API/WS auth)
15
+ */
16
+ validateLocalToken(token: string): boolean;
17
+ /**
18
+ * Get the local session token (for passing to child processes)
19
+ */
20
+ getLocalToken(): string;
21
+ /**
22
+ * Read the local session token from disk (static utility for clients)
23
+ */
24
+ static readLocalToken(): string | null;
25
+ }
26
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../server/services/auth.ts"],"names":[],"mappings":"AAkBA,qBAAa,WAAW;IACtB,OAAO,CAAC,UAAU,CAAQ;;IAM1B;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;OAEG;IACH,OAAO,CAAC,UAAU;IAQlB;;OAEG;IACH,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAI1C;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,MAAM,CAAC,cAAc,IAAI,MAAM,GAAG,IAAI;CAWvC"}
@@ -0,0 +1,71 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file for details.
3
+ /**
4
+ * Authentication Service
5
+ *
6
+ * Manages local session token for localhost API/WebSocket auth.
7
+ * All mstro instances on a machine share a single token from ~/.mstro/session-token.
8
+ * The token is created once (by `mstro login` or first server start) and reused.
9
+ */
10
+ import { randomBytes } from 'node:crypto';
11
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
12
+ import { homedir } from 'node:os';
13
+ import { join } from 'node:path';
14
+ const SESSION_TOKEN_PATH = join(homedir(), '.mstro', 'session-token');
15
+ export class AuthService {
16
+ localToken;
17
+ constructor() {
18
+ this.localToken = this.loadOrCreateToken();
19
+ }
20
+ /**
21
+ * Load existing session token from disk, or create one if missing.
22
+ * This ensures all mstro instances on the same machine share the same token.
23
+ */
24
+ loadOrCreateToken() {
25
+ const existing = AuthService.readLocalToken();
26
+ if (existing) {
27
+ return existing;
28
+ }
29
+ const token = randomBytes(32).toString('hex');
30
+ this.writeToken(token);
31
+ return token;
32
+ }
33
+ /**
34
+ * Write session token to ~/.mstro/session-token
35
+ */
36
+ writeToken(token) {
37
+ const dir = join(homedir(), '.mstro');
38
+ if (!existsSync(dir)) {
39
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
40
+ }
41
+ writeFileSync(SESSION_TOKEN_PATH, token, { mode: 0o600 });
42
+ }
43
+ /**
44
+ * Validate the local session token (used for localhost API/WS auth)
45
+ */
46
+ validateLocalToken(token) {
47
+ return token === this.localToken;
48
+ }
49
+ /**
50
+ * Get the local session token (for passing to child processes)
51
+ */
52
+ getLocalToken() {
53
+ return this.localToken;
54
+ }
55
+ /**
56
+ * Read the local session token from disk (static utility for clients)
57
+ */
58
+ static readLocalToken() {
59
+ try {
60
+ if (existsSync(SESSION_TOKEN_PATH)) {
61
+ const token = readFileSync(SESSION_TOKEN_PATH, 'utf-8').trim();
62
+ if (token.length > 0) {
63
+ return token;
64
+ }
65
+ }
66
+ }
67
+ catch { }
68
+ return null;
69
+ }
70
+ }
71
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../server/services/auth.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,gEAAgE;AAEhE;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAA;AAErE,MAAM,OAAO,WAAW;IACd,UAAU,CAAQ;IAE1B;QACE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAA;IAC5C,CAAC;IAED;;;OAGG;IACK,iBAAiB;QACvB,MAAM,QAAQ,GAAG,WAAW,CAAC,cAAc,EAAE,CAAA;QAC7C,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,QAAQ,CAAA;QACjB,CAAC;QAED,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;QAC7C,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;QACtB,OAAO,KAAK,CAAA;IACd,CAAC;IAED;;OAEG;IACK,UAAU,CAAC,KAAa;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAA;QACrC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QAClD,CAAC;QACD,aAAa,CAAC,kBAAkB,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IAC3D,CAAC;IAED;;OAEG;IACH,kBAAkB,CAAC,KAAa;QAC9B,OAAO,KAAK,KAAK,IAAI,CAAC,UAAU,CAAA;IAClC,CAAC;IAED;;OAEG;IACH,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAA;IACxB,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,cAAc;QACnB,IAAI,CAAC;YACH,IAAI,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBACnC,MAAM,KAAK,GAAG,YAAY,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAA;gBAC9D,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,OAAO,KAAK,CAAA;gBACd,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACV,OAAO,IAAI,CAAA;IACb,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Get the persistent client ID, creating one if it doesn't exist.
3
+ * This ID is unique to this machine's ~/.mstro directory.
4
+ */
5
+ export declare function getClientId(): string;
6
+ /**
7
+ * Get the client ID file path (for debugging/display)
8
+ */
9
+ export declare function getClientIdPath(): string;
10
+ //# sourceMappingURL=client-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-id.d.ts","sourceRoot":"","sources":["../../../server/services/client-id.ts"],"names":[],"mappings":"AA0BA;;;GAGG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAsBpC;AAUD;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
@@ -0,0 +1,61 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file for details.
3
+ /**
4
+ * Client ID Service
5
+ *
6
+ * Generates and persists a unique client identifier that survives server restarts.
7
+ * This ID is used to distinguish between different user home directories on different machines.
8
+ *
9
+ * Storage: ~/.mstro/client-id
10
+ */
11
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
12
+ import { homedir } from 'node:os';
13
+ import { join } from 'node:path';
14
+ const MSTRO_DIR = join(homedir(), '.mstro');
15
+ const CLIENT_ID_FILE = join(MSTRO_DIR, 'client-id');
16
+ /**
17
+ * Generate a new UUID v4
18
+ */
19
+ function generateUUID() {
20
+ return crypto.randomUUID();
21
+ }
22
+ /**
23
+ * Get the persistent client ID, creating one if it doesn't exist.
24
+ * This ID is unique to this machine's ~/.mstro directory.
25
+ */
26
+ export function getClientId() {
27
+ // Ensure ~/.mstro directory exists
28
+ if (!existsSync(MSTRO_DIR)) {
29
+ mkdirSync(MSTRO_DIR, { recursive: true, mode: 0o700 });
30
+ }
31
+ // Try to read existing client ID
32
+ if (existsSync(CLIENT_ID_FILE)) {
33
+ try {
34
+ const id = readFileSync(CLIENT_ID_FILE, 'utf-8').trim();
35
+ if (id && isValidUUID(id)) {
36
+ return id;
37
+ }
38
+ }
39
+ catch {
40
+ // File exists but couldn't be read, generate new one
41
+ }
42
+ }
43
+ // Generate and persist a new client ID
44
+ const newId = generateUUID();
45
+ writeFileSync(CLIENT_ID_FILE, newId, 'utf-8');
46
+ return newId;
47
+ }
48
+ /**
49
+ * Validate UUID format
50
+ */
51
+ function isValidUUID(id) {
52
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
53
+ return uuidRegex.test(id);
54
+ }
55
+ /**
56
+ * Get the client ID file path (for debugging/display)
57
+ */
58
+ export function getClientIdPath() {
59
+ return CLIENT_ID_FILE;
60
+ }
61
+ //# sourceMappingURL=client-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-id.js","sourceRoot":"","sources":["../../../server/services/client-id.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,gEAAgE;AAEhE;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAA;AAC3C,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAA;AAEnD;;GAEG;AACH,SAAS,YAAY;IACnB,OAAO,MAAM,CAAC,UAAU,EAAE,CAAA;AAC5B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW;IACzB,mCAAmC;IACnC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IACxD,CAAC;IAED,iCAAiC;IACjC,IAAI,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAA;YACvD,IAAI,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC1B,OAAO,EAAE,CAAA;YACX,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,qDAAqD;QACvD,CAAC;IACH,CAAC;IAED,uCAAuC;IACvC,MAAM,KAAK,GAAG,YAAY,EAAE,CAAA;IAC5B,aAAa,CAAC,cAAc,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;IAC7C,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,EAAU;IAC7B,MAAM,SAAS,GAAG,wEAAwE,CAAA;IAC1F,OAAO,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,cAAc,CAAA;AACvB,CAAC"}