mstro-app 0.4.39 → 0.4.43

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 (197) hide show
  1. package/bin/commands/login.js +17 -7
  2. package/bin/commands/logout.js +14 -6
  3. package/bin/commands/status.js +9 -3
  4. package/bin/commands/whoami.js +10 -4
  5. package/bin/mstro.js +11 -1
  6. package/dist/server/cli/headless/claude-invoker-stream.d.ts.map +1 -1
  7. package/dist/server/cli/headless/claude-invoker-stream.js +1 -0
  8. package/dist/server/cli/headless/claude-invoker-stream.js.map +1 -1
  9. package/dist/server/cli/headless/index.d.ts +1 -0
  10. package/dist/server/cli/headless/index.d.ts.map +1 -1
  11. package/dist/server/cli/headless/index.js +2 -0
  12. package/dist/server/cli/headless/index.js.map +1 -1
  13. package/dist/server/cli/headless/resilient-runner.d.ts +47 -0
  14. package/dist/server/cli/headless/resilient-runner.d.ts.map +1 -0
  15. package/dist/server/cli/headless/resilient-runner.js +234 -0
  16. package/dist/server/cli/headless/resilient-runner.js.map +1 -0
  17. package/dist/server/cli/headless/retry-strategies.d.ts +44 -0
  18. package/dist/server/cli/headless/retry-strategies.d.ts.map +1 -0
  19. package/dist/server/cli/headless/retry-strategies.js +262 -0
  20. package/dist/server/cli/headless/retry-strategies.js.map +1 -0
  21. package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
  22. package/dist/server/cli/headless/stall-assessor.js +5 -0
  23. package/dist/server/cli/headless/stall-assessor.js.map +1 -1
  24. package/dist/server/cli/headless/tool-watchdog.d.ts +2 -0
  25. package/dist/server/cli/headless/tool-watchdog.d.ts.map +1 -1
  26. package/dist/server/cli/headless/tool-watchdog.js +31 -4
  27. package/dist/server/cli/headless/tool-watchdog.js.map +1 -1
  28. package/dist/server/cli/improvisation-retry.d.ts.map +1 -1
  29. package/dist/server/cli/improvisation-retry.js +1 -30
  30. package/dist/server/cli/improvisation-retry.js.map +1 -1
  31. package/dist/server/cli/improvisation-session-manager.d.ts +1 -0
  32. package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
  33. package/dist/server/cli/improvisation-session-manager.js +16 -3
  34. package/dist/server/cli/improvisation-session-manager.js.map +1 -1
  35. package/dist/server/cli/prompt-builders.d.ts.map +1 -1
  36. package/dist/server/cli/prompt-builders.js +31 -13
  37. package/dist/server/cli/prompt-builders.js.map +1 -1
  38. package/dist/server/index.js +1 -9
  39. package/dist/server/index.js.map +1 -1
  40. package/dist/server/mcp/bouncer-cli.js +5 -4
  41. package/dist/server/mcp/bouncer-cli.js.map +1 -1
  42. package/dist/server/mcp/bouncer-haiku.js +1 -1
  43. package/dist/server/mcp/bouncer-haiku.js.map +1 -1
  44. package/dist/server/mcp/bouncer-integration.d.ts.map +1 -1
  45. package/dist/server/mcp/bouncer-integration.js +14 -8
  46. package/dist/server/mcp/bouncer-integration.js.map +1 -1
  47. package/dist/server/mcp/security-patterns.js +1 -1
  48. package/dist/server/mcp/security-patterns.js.map +1 -1
  49. package/dist/server/services/plan/composer.d.ts.map +1 -1
  50. package/dist/server/services/plan/composer.js +19 -9
  51. package/dist/server/services/plan/composer.js.map +1 -1
  52. package/dist/server/services/plan/executor.d.ts +6 -1
  53. package/dist/server/services/plan/executor.d.ts.map +1 -1
  54. package/dist/server/services/plan/executor.js +158 -76
  55. package/dist/server/services/plan/executor.js.map +1 -1
  56. package/dist/server/services/plan/front-matter.d.ts +1 -0
  57. package/dist/server/services/plan/front-matter.d.ts.map +1 -1
  58. package/dist/server/services/plan/front-matter.js +6 -0
  59. package/dist/server/services/plan/front-matter.js.map +1 -1
  60. package/dist/server/services/plan/issue-classification.d.ts +11 -0
  61. package/dist/server/services/plan/issue-classification.d.ts.map +1 -0
  62. package/dist/server/services/plan/issue-classification.js +20 -0
  63. package/dist/server/services/plan/issue-classification.js.map +1 -0
  64. package/dist/server/services/plan/issue-prompt-builder.d.ts.map +1 -1
  65. package/dist/server/services/plan/issue-prompt-builder.js +7 -4
  66. package/dist/server/services/plan/issue-prompt-builder.js.map +1 -1
  67. package/dist/server/services/plan/issue-retry.d.ts +0 -5
  68. package/dist/server/services/plan/issue-retry.d.ts.map +1 -1
  69. package/dist/server/services/plan/issue-retry.js +12 -241
  70. package/dist/server/services/plan/issue-retry.js.map +1 -1
  71. package/dist/server/services/plan/parser-core.d.ts.map +1 -1
  72. package/dist/server/services/plan/parser-core.js +1 -0
  73. package/dist/server/services/plan/parser-core.js.map +1 -1
  74. package/dist/server/services/plan/review-gate.d.ts.map +1 -1
  75. package/dist/server/services/plan/review-gate.js +9 -6
  76. package/dist/server/services/plan/review-gate.js.map +1 -1
  77. package/dist/server/services/plan/types.d.ts +1 -0
  78. package/dist/server/services/plan/types.d.ts.map +1 -1
  79. package/dist/server/services/platform-credentials.d.ts.map +1 -1
  80. package/dist/server/services/platform-credentials.js +11 -4
  81. package/dist/server/services/platform-credentials.js.map +1 -1
  82. package/dist/server/services/terminal/pty-manager.d.ts.map +1 -1
  83. package/dist/server/services/terminal/pty-manager.js +7 -1
  84. package/dist/server/services/terminal/pty-manager.js.map +1 -1
  85. package/dist/server/services/websocket/handler-context.d.ts +2 -0
  86. package/dist/server/services/websocket/handler-context.d.ts.map +1 -1
  87. package/dist/server/services/websocket/handler.d.ts +2 -0
  88. package/dist/server/services/websocket/handler.d.ts.map +1 -1
  89. package/dist/server/services/websocket/handler.js +18 -7
  90. package/dist/server/services/websocket/handler.js.map +1 -1
  91. package/dist/server/services/websocket/plan-execution-handlers.js +6 -6
  92. package/dist/server/services/websocket/plan-execution-handlers.js.map +1 -1
  93. package/dist/server/services/websocket/quality-fix-agent.d.ts.map +1 -1
  94. package/dist/server/services/websocket/quality-fix-agent.js +90 -42
  95. package/dist/server/services/websocket/quality-fix-agent.js.map +1 -1
  96. package/dist/server/services/websocket/quality-handlers.d.ts.map +1 -1
  97. package/dist/server/services/websocket/quality-handlers.js +48 -7
  98. package/dist/server/services/websocket/quality-handlers.js.map +1 -1
  99. package/dist/server/services/websocket/quality-persistence.d.ts +22 -0
  100. package/dist/server/services/websocket/quality-persistence.d.ts.map +1 -1
  101. package/dist/server/services/websocket/quality-persistence.js +48 -1
  102. package/dist/server/services/websocket/quality-persistence.js.map +1 -1
  103. package/dist/server/services/websocket/quality-review-agent.d.ts.map +1 -1
  104. package/dist/server/services/websocket/quality-review-agent.js +74 -32
  105. package/dist/server/services/websocket/quality-review-agent.js.map +1 -1
  106. package/dist/server/services/websocket/quality-tools.d.ts.map +1 -1
  107. package/dist/server/services/websocket/quality-tools.js +18 -18
  108. package/dist/server/services/websocket/quality-tools.js.map +1 -1
  109. package/dist/server/services/websocket/skill-handlers.d.ts +3 -1
  110. package/dist/server/services/websocket/skill-handlers.d.ts.map +1 -1
  111. package/dist/server/services/websocket/skill-handlers.js +52 -41
  112. package/dist/server/services/websocket/skill-handlers.js.map +1 -1
  113. package/dist/server/services/websocket/skill-watcher.d.ts +17 -0
  114. package/dist/server/services/websocket/skill-watcher.d.ts.map +1 -0
  115. package/dist/server/services/websocket/skill-watcher.js +85 -0
  116. package/dist/server/services/websocket/skill-watcher.js.map +1 -0
  117. package/dist/server/services/websocket/types.d.ts +2 -268
  118. package/dist/server/services/websocket/types.d.ts.map +1 -1
  119. package/dist/server/services/websocket/types.js +0 -4
  120. package/dist/server/services/websocket/types.js.map +1 -1
  121. package/package.json +1 -1
  122. package/server/cli/headless/claude-invoker-stream.ts +1 -0
  123. package/server/cli/headless/index.ts +2 -0
  124. package/server/cli/headless/resilient-runner.ts +354 -0
  125. package/server/cli/headless/retry-strategies.ts +330 -0
  126. package/server/cli/headless/stall-assessor.ts +5 -0
  127. package/server/cli/headless/tool-watchdog.ts +40 -4
  128. package/server/cli/improvisation-retry.ts +1 -32
  129. package/server/cli/improvisation-session-manager.ts +17 -3
  130. package/server/cli/prompt-builders.ts +33 -12
  131. package/server/index.ts +1 -9
  132. package/server/mcp/bouncer-cli.ts +5 -4
  133. package/server/mcp/bouncer-haiku.ts +1 -1
  134. package/server/mcp/bouncer-integration.ts +15 -8
  135. package/server/mcp/security-patterns.ts +1 -1
  136. package/server/services/plan/agents/code-review.md +109 -0
  137. package/server/services/plan/agents/commit-message.md +26 -0
  138. package/server/services/plan/agents/fix-quality.md +24 -0
  139. package/server/services/plan/agents/pr-description.md +28 -0
  140. package/server/services/plan/composer.ts +20 -9
  141. package/server/services/plan/executor.ts +160 -76
  142. package/server/services/plan/front-matter.ts +7 -0
  143. package/server/services/plan/issue-classification.ts +21 -0
  144. package/server/services/plan/issue-prompt-builder.ts +8 -4
  145. package/server/services/plan/issue-retry.ts +15 -330
  146. package/server/services/plan/parser-core.ts +1 -0
  147. package/server/services/plan/review-gate.ts +9 -6
  148. package/server/services/plan/types.ts +3 -0
  149. package/server/services/platform-credentials.ts +10 -4
  150. package/server/services/terminal/pty-manager.ts +7 -1
  151. package/server/services/websocket/handler-context.ts +2 -0
  152. package/server/services/websocket/handler.ts +18 -8
  153. package/server/services/websocket/plan-execution-handlers.ts +7 -7
  154. package/server/services/websocket/quality-fix-agent.ts +86 -44
  155. package/server/services/websocket/quality-handlers.ts +48 -7
  156. package/server/services/websocket/quality-persistence.ts +75 -1
  157. package/server/services/websocket/quality-review-agent.ts +70 -31
  158. package/server/services/websocket/quality-tools.ts +16 -14
  159. package/server/services/websocket/skill-handlers.ts +50 -40
  160. package/server/services/websocket/skill-watcher.ts +79 -0
  161. package/server/services/websocket/types.ts +0 -311
  162. package/dist/server/services/deploy/ai-broker.d.ts +0 -63
  163. package/dist/server/services/deploy/ai-broker.d.ts.map +0 -1
  164. package/dist/server/services/deploy/ai-broker.js +0 -360
  165. package/dist/server/services/deploy/ai-broker.js.map +0 -1
  166. package/dist/server/services/deploy/board-execution-handler.d.ts +0 -114
  167. package/dist/server/services/deploy/board-execution-handler.d.ts.map +0 -1
  168. package/dist/server/services/deploy/board-execution-handler.js +0 -621
  169. package/dist/server/services/deploy/board-execution-handler.js.map +0 -1
  170. package/dist/server/services/deploy/credentials.d.ts +0 -35
  171. package/dist/server/services/deploy/credentials.d.ts.map +0 -1
  172. package/dist/server/services/deploy/credentials.js +0 -177
  173. package/dist/server/services/deploy/credentials.js.map +0 -1
  174. package/dist/server/services/deploy/deploy-ai-service.d.ts +0 -107
  175. package/dist/server/services/deploy/deploy-ai-service.d.ts.map +0 -1
  176. package/dist/server/services/deploy/deploy-ai-service.js +0 -294
  177. package/dist/server/services/deploy/deploy-ai-service.js.map +0 -1
  178. package/dist/server/services/deploy/headless-session-handler.d.ts +0 -94
  179. package/dist/server/services/deploy/headless-session-handler.d.ts.map +0 -1
  180. package/dist/server/services/deploy/headless-session-handler.js +0 -266
  181. package/dist/server/services/deploy/headless-session-handler.js.map +0 -1
  182. package/dist/server/services/websocket/deploy-handlers.d.ts +0 -14
  183. package/dist/server/services/websocket/deploy-handlers.d.ts.map +0 -1
  184. package/dist/server/services/websocket/deploy-handlers.js +0 -409
  185. package/dist/server/services/websocket/deploy-handlers.js.map +0 -1
  186. package/dist/server/services/websocket/handlers/deploy-handlers.d.ts +0 -11
  187. package/dist/server/services/websocket/handlers/deploy-handlers.d.ts.map +0 -1
  188. package/dist/server/services/websocket/handlers/deploy-handlers.js +0 -176
  189. package/dist/server/services/websocket/handlers/deploy-handlers.js.map +0 -1
  190. package/server/cli/headless/RESEARCH.md +0 -627
  191. package/server/services/deploy/ai-broker.ts +0 -512
  192. package/server/services/deploy/board-execution-handler.ts +0 -847
  193. package/server/services/deploy/credentials.ts +0 -200
  194. package/server/services/deploy/deploy-ai-service.ts +0 -401
  195. package/server/services/deploy/headless-session-handler.ts +0 -414
  196. package/server/services/websocket/deploy-handlers.ts +0 -544
  197. package/server/services/websocket/handlers/deploy-handlers.ts +0 -228
@@ -1,228 +0,0 @@
1
- // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
- // Licensed under the MIT License. See LICENSE file for details.
3
-
4
- /**
5
- * Deploy HTTP Handler
6
- *
7
- * Handles deployHttpRequest messages from the platform server relay.
8
- * Proxies HTTP requests to the developer's local server and returns
9
- * the response back through the WebSocket relay.
10
- */
11
-
12
- import type { HandlerContext } from '../handler-context.js';
13
- import type { DeployHttpRequestData, DeployHttpResponseChunkData, DeployHttpResponseData, WebSocketMessage, WSContext } from '../types.js';
14
-
15
- /** Hop-by-hop headers that must not be forwarded through a proxy (RFC 2616 §13.5.1) */
16
- const HOP_BY_HOP_HEADERS = new Set([
17
- 'connection',
18
- 'keep-alive',
19
- 'transfer-encoding',
20
- 'te',
21
- 'trailers',
22
- 'upgrade',
23
- ]);
24
-
25
- /** Request timeout in milliseconds (30 seconds) */
26
- const REQUEST_TIMEOUT_MS = 30_000;
27
-
28
- /** Maximum total header size in bytes (16 KB) */
29
- const MAX_HEADER_SIZE_BYTES = 16_384;
30
-
31
- /** Chunking threshold: responses larger than 1 MB are streamed in chunks */
32
- const CHUNK_THRESHOLD_BYTES = 1_048_576;
33
-
34
- /** Size of each chunk (~256 KB of raw data → ~341 KB base64) */
35
- const CHUNK_SIZE_BYTES = 262_144;
36
-
37
- function isHopByHopHeader(name: string): boolean {
38
- const lower = name.toLowerCase();
39
- return HOP_BY_HOP_HEADERS.has(lower) || lower.startsWith('proxy-');
40
- }
41
-
42
- function stripHopByHopHeaders(headers: Record<string, string>): Record<string, string> {
43
- const result: Record<string, string> = {};
44
- for (const [key, value] of Object.entries(headers)) {
45
- if (!isHopByHopHeader(key)) {
46
- result[key] = value;
47
- }
48
- }
49
- return result;
50
- }
51
-
52
- /** Check headers for null bytes or CRLF injection attempts */
53
- function containsHeaderInjection(headers: Record<string, string>): boolean {
54
- for (const [key, value] of Object.entries(headers)) {
55
- if (key.includes('\0') || value.includes('\0')) return true;
56
- if (/\r|\n/.test(key) || /\r|\n/.test(value)) return true;
57
- }
58
- return false;
59
- }
60
-
61
- /** Calculate total size of request headers in bytes */
62
- function calculateHeaderSize(headers: Record<string, string>): number {
63
- let size = 0;
64
- for (const [key, value] of Object.entries(headers)) {
65
- // key: value\r\n
66
- size += key.length + 2 + value.length + 2;
67
- }
68
- return size;
69
- }
70
-
71
- function sendDeployHttpResponse(
72
- ctx: HandlerContext,
73
- ws: WSContext,
74
- data: DeployHttpResponseData,
75
- ): void {
76
- ctx.send(ws, { type: 'deployHttpResponse', data });
77
- }
78
-
79
- /** Send a large response body in chunks via deployHttpResponseChunk messages */
80
- function sendChunkedResponse(
81
- ctx: HandlerContext,
82
- ws: WSContext,
83
- requestId: string,
84
- status: number,
85
- headers: Record<string, string>,
86
- bodyBuffer: Buffer,
87
- ): void {
88
- const totalChunks = Math.ceil(bodyBuffer.length / CHUNK_SIZE_BYTES);
89
-
90
- for (let i = 0; i < totalChunks; i++) {
91
- const start = i * CHUNK_SIZE_BYTES;
92
- const end = Math.min(start + CHUNK_SIZE_BYTES, bodyBuffer.length);
93
- const chunk = bodyBuffer.subarray(start, end);
94
- const isLast = i === totalChunks - 1;
95
-
96
- const chunkData: DeployHttpResponseChunkData = {
97
- requestId,
98
- chunkIndex: i,
99
- totalChunks,
100
- data: chunk.toString('base64'),
101
- isLast,
102
- };
103
-
104
- // Include status and headers only in the first chunk
105
- if (i === 0) {
106
- chunkData.status = status;
107
- chunkData.headers = headers;
108
- }
109
-
110
- ctx.send(ws, { type: 'deployHttpResponseChunk', data: chunkData });
111
- }
112
- }
113
-
114
- /** Validate the incoming deploy HTTP request data. Returns an error response body string or null if valid. */
115
- function validateDeployRequest(
116
- data: DeployHttpRequestData,
117
- ): { status: number; body: string } | null {
118
- if (!data?.requestId || !data?.method || !data?.url || !data?.port) {
119
- return { status: 400, body: 'Bad Request: missing required fields (requestId, method, url, port)' };
120
- }
121
- if (data.headers && containsHeaderInjection(data.headers)) {
122
- return { status: 400, body: 'Bad Request: headers contain null bytes or CRLF injection' };
123
- }
124
- if (data.headers && calculateHeaderSize(data.headers) > MAX_HEADER_SIZE_BYTES) {
125
- return { status: 431, body: 'Request Header Fields Too Large: total headers exceed 16KB' };
126
- }
127
- return null;
128
- }
129
-
130
- /** Classify a fetch error into an HTTP status code and message. */
131
- function classifyFetchError(error: unknown): { status: number; body: string } {
132
- if (error instanceof Error) {
133
- if (error.name === 'AbortError') {
134
- return { status: 504, body: 'Gateway Timeout' };
135
- }
136
- if (isConnectionRefused(error)) {
137
- return { status: 502, body: 'Bad Gateway: target server is not running' };
138
- }
139
- }
140
- return { status: 502, body: 'Bad Gateway' };
141
- }
142
-
143
- export async function handleDeployHttpRequest(
144
- ctx: HandlerContext,
145
- ws: WSContext,
146
- msg: WebSocketMessage,
147
- ): Promise<void> {
148
- const data = msg.data as DeployHttpRequestData;
149
-
150
- const validationError = validateDeployRequest(data);
151
- if (validationError) {
152
- sendDeployHttpResponse(ctx, ws, {
153
- requestId: data?.requestId || 'unknown',
154
- status: validationError.status,
155
- headers: {},
156
- body: validationError.body,
157
- });
158
- return;
159
- }
160
-
161
- // Build local URL: 127.0.0.1:{port}{path with query string}
162
- // Use explicit IPv4 loopback to avoid IPv6 resolution issues on some systems
163
- const localUrl = `http://127.0.0.1:${data.port}${data.url}`;
164
-
165
- try {
166
- const requestHeaders = stripHopByHopHeaders(data.headers);
167
-
168
- // Only include body for methods that support it
169
- const hasBody = data.body !== undefined && data.method !== 'GET' && data.method !== 'HEAD';
170
-
171
- const controller = new AbortController();
172
- const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
173
-
174
- let response: Response;
175
- try {
176
- response = await fetch(localUrl, {
177
- method: data.method,
178
- headers: requestHeaders,
179
- body: hasBody ? data.body : undefined,
180
- signal: controller.signal,
181
- redirect: 'manual',
182
- });
183
- } finally {
184
- clearTimeout(timeout);
185
- }
186
-
187
- // Serialize response headers, stripping hop-by-hop
188
- const responseHeaders: Record<string, string> = {};
189
- response.headers.forEach((value, key) => {
190
- if (!isHopByHopHeader(key)) {
191
- responseHeaders[key] = value;
192
- }
193
- });
194
-
195
- // Read response as binary to handle both text and binary payloads
196
- const bodyBuffer = Buffer.from(await response.arrayBuffer());
197
-
198
- // Stream large responses in chunks
199
- if (bodyBuffer.length > CHUNK_THRESHOLD_BYTES) {
200
- sendChunkedResponse(ctx, ws, data.requestId, response.status, responseHeaders, bodyBuffer);
201
- return;
202
- }
203
-
204
- // Small response — send as a single message
205
- sendDeployHttpResponse(ctx, ws, {
206
- requestId: data.requestId,
207
- status: response.status,
208
- headers: responseHeaders,
209
- body: bodyBuffer.toString('utf-8'),
210
- });
211
- } catch (error: unknown) {
212
- const { status, body } = classifyFetchError(error);
213
-
214
- sendDeployHttpResponse(ctx, ws, {
215
- requestId: data.requestId,
216
- status,
217
- headers: {},
218
- body,
219
- });
220
- }
221
- }
222
-
223
- /** Detect ECONNREFUSED across Node.js error shapes */
224
- function isConnectionRefused(error: Error): boolean {
225
- if (error.message.includes('ECONNREFUSED')) return true;
226
- const cause = (error as Error & { cause?: { code?: string } }).cause;
227
- return cause?.code === 'ECONNREFUSED';
228
- }