mstro-app 0.4.2 → 0.4.4

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 (342) hide show
  1. package/bin/mstro.js +119 -40
  2. package/dist/server/cli/headless/claude-invoker-process.d.ts +11 -0
  3. package/dist/server/cli/headless/claude-invoker-process.d.ts.map +1 -0
  4. package/dist/server/cli/headless/claude-invoker-process.js +140 -0
  5. package/dist/server/cli/headless/claude-invoker-process.js.map +1 -0
  6. package/dist/server/cli/headless/claude-invoker-stall.d.ts +40 -0
  7. package/dist/server/cli/headless/claude-invoker-stall.d.ts.map +1 -0
  8. package/dist/server/cli/headless/claude-invoker-stall.js +98 -0
  9. package/dist/server/cli/headless/claude-invoker-stall.js.map +1 -0
  10. package/dist/server/cli/headless/claude-invoker-stream.d.ts +44 -0
  11. package/dist/server/cli/headless/claude-invoker-stream.d.ts.map +1 -0
  12. package/dist/server/cli/headless/claude-invoker-stream.js +276 -0
  13. package/dist/server/cli/headless/claude-invoker-stream.js.map +1 -0
  14. package/dist/server/cli/headless/claude-invoker-tools.d.ts +21 -0
  15. package/dist/server/cli/headless/claude-invoker-tools.d.ts.map +1 -0
  16. package/dist/server/cli/headless/claude-invoker-tools.js +137 -0
  17. package/dist/server/cli/headless/claude-invoker-tools.js.map +1 -0
  18. package/dist/server/cli/headless/claude-invoker.d.ts +6 -4
  19. package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -1
  20. package/dist/server/cli/headless/claude-invoker.js +10 -804
  21. package/dist/server/cli/headless/claude-invoker.js.map +1 -1
  22. package/dist/server/cli/headless/haiku-assessments.d.ts +62 -0
  23. package/dist/server/cli/headless/haiku-assessments.d.ts.map +1 -0
  24. package/dist/server/cli/headless/haiku-assessments.js +281 -0
  25. package/dist/server/cli/headless/haiku-assessments.js.map +1 -0
  26. package/dist/server/cli/headless/headless-logger.d.ts +3 -2
  27. package/dist/server/cli/headless/headless-logger.d.ts.map +1 -1
  28. package/dist/server/cli/headless/headless-logger.js +28 -5
  29. package/dist/server/cli/headless/headless-logger.js.map +1 -1
  30. package/dist/server/cli/headless/native-timeout-detector.d.ts +44 -0
  31. package/dist/server/cli/headless/native-timeout-detector.d.ts.map +1 -0
  32. package/dist/server/cli/headless/native-timeout-detector.js +99 -0
  33. package/dist/server/cli/headless/native-timeout-detector.js.map +1 -0
  34. package/dist/server/cli/headless/stall-assessor.d.ts +2 -110
  35. package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
  36. package/dist/server/cli/headless/stall-assessor.js +65 -457
  37. package/dist/server/cli/headless/stall-assessor.js.map +1 -1
  38. package/dist/server/cli/headless/types.d.ts +4 -1
  39. package/dist/server/cli/headless/types.d.ts.map +1 -1
  40. package/dist/server/cli/improvisation-attachments.d.ts +21 -0
  41. package/dist/server/cli/improvisation-attachments.d.ts.map +1 -0
  42. package/dist/server/cli/improvisation-attachments.js +116 -0
  43. package/dist/server/cli/improvisation-attachments.js.map +1 -0
  44. package/dist/server/cli/improvisation-retry.d.ts +52 -0
  45. package/dist/server/cli/improvisation-retry.d.ts.map +1 -0
  46. package/dist/server/cli/improvisation-retry.js +434 -0
  47. package/dist/server/cli/improvisation-retry.js.map +1 -0
  48. package/dist/server/cli/improvisation-session-manager.d.ts +10 -266
  49. package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
  50. package/dist/server/cli/improvisation-session-manager.js +117 -1079
  51. package/dist/server/cli/improvisation-session-manager.js.map +1 -1
  52. package/dist/server/cli/improvisation-types.d.ts +86 -0
  53. package/dist/server/cli/improvisation-types.d.ts.map +1 -0
  54. package/dist/server/cli/improvisation-types.js +10 -0
  55. package/dist/server/cli/improvisation-types.js.map +1 -0
  56. package/dist/server/cli/prompt-builders.d.ts +68 -0
  57. package/dist/server/cli/prompt-builders.d.ts.map +1 -0
  58. package/dist/server/cli/prompt-builders.js +312 -0
  59. package/dist/server/cli/prompt-builders.js.map +1 -0
  60. package/dist/server/index.js +33 -212
  61. package/dist/server/index.js.map +1 -1
  62. package/dist/server/mcp/bouncer-haiku.d.ts +10 -0
  63. package/dist/server/mcp/bouncer-haiku.d.ts.map +1 -0
  64. package/dist/server/mcp/bouncer-haiku.js +152 -0
  65. package/dist/server/mcp/bouncer-haiku.js.map +1 -0
  66. package/dist/server/mcp/bouncer-integration.d.ts +3 -4
  67. package/dist/server/mcp/bouncer-integration.d.ts.map +1 -1
  68. package/dist/server/mcp/bouncer-integration.js +50 -196
  69. package/dist/server/mcp/bouncer-integration.js.map +1 -1
  70. package/dist/server/mcp/security-analysis.d.ts +38 -0
  71. package/dist/server/mcp/security-analysis.d.ts.map +1 -0
  72. package/dist/server/mcp/security-analysis.js +183 -0
  73. package/dist/server/mcp/security-analysis.js.map +1 -0
  74. package/dist/server/mcp/security-audit.d.ts +1 -1
  75. package/dist/server/mcp/security-audit.d.ts.map +1 -1
  76. package/dist/server/mcp/security-patterns.d.ts +1 -25
  77. package/dist/server/mcp/security-patterns.d.ts.map +1 -1
  78. package/dist/server/mcp/security-patterns.js +55 -260
  79. package/dist/server/mcp/security-patterns.js.map +1 -1
  80. package/dist/server/server-setup.d.ts +22 -0
  81. package/dist/server/server-setup.d.ts.map +1 -0
  82. package/dist/server/server-setup.js +101 -0
  83. package/dist/server/server-setup.js.map +1 -0
  84. package/dist/server/services/file-explorer-ops.d.ts +24 -0
  85. package/dist/server/services/file-explorer-ops.d.ts.map +1 -0
  86. package/dist/server/services/file-explorer-ops.js +211 -0
  87. package/dist/server/services/file-explorer-ops.js.map +1 -0
  88. package/dist/server/services/files.d.ts +2 -85
  89. package/dist/server/services/files.d.ts.map +1 -1
  90. package/dist/server/services/files.js +7 -427
  91. package/dist/server/services/files.js.map +1 -1
  92. package/dist/server/services/plan/composer.d.ts +1 -1
  93. package/dist/server/services/plan/composer.d.ts.map +1 -1
  94. package/dist/server/services/plan/composer.js +118 -32
  95. package/dist/server/services/plan/composer.js.map +1 -1
  96. package/dist/server/services/plan/config-installer.d.ts +25 -0
  97. package/dist/server/services/plan/config-installer.d.ts.map +1 -0
  98. package/dist/server/services/plan/config-installer.js +182 -0
  99. package/dist/server/services/plan/config-installer.js.map +1 -0
  100. package/dist/server/services/plan/dependency-resolver.d.ts +1 -1
  101. package/dist/server/services/plan/dependency-resolver.d.ts.map +1 -1
  102. package/dist/server/services/plan/dependency-resolver.js +4 -1
  103. package/dist/server/services/plan/dependency-resolver.js.map +1 -1
  104. package/dist/server/services/plan/executor.d.ts +38 -74
  105. package/dist/server/services/plan/executor.d.ts.map +1 -1
  106. package/dist/server/services/plan/executor.js +274 -460
  107. package/dist/server/services/plan/executor.js.map +1 -1
  108. package/dist/server/services/plan/front-matter.d.ts +18 -0
  109. package/dist/server/services/plan/front-matter.d.ts.map +1 -0
  110. package/dist/server/services/plan/front-matter.js +44 -0
  111. package/dist/server/services/plan/front-matter.js.map +1 -0
  112. package/dist/server/services/plan/output-manager.d.ts +22 -0
  113. package/dist/server/services/plan/output-manager.d.ts.map +1 -0
  114. package/dist/server/services/plan/output-manager.js +97 -0
  115. package/dist/server/services/plan/output-manager.js.map +1 -0
  116. package/dist/server/services/plan/parser-core.d.ts +20 -0
  117. package/dist/server/services/plan/parser-core.d.ts.map +1 -0
  118. package/dist/server/services/plan/parser-core.js +350 -0
  119. package/dist/server/services/plan/parser-core.js.map +1 -0
  120. package/dist/server/services/plan/parser-migration.d.ts +5 -0
  121. package/dist/server/services/plan/parser-migration.d.ts.map +1 -0
  122. package/dist/server/services/plan/parser-migration.js +124 -0
  123. package/dist/server/services/plan/parser-migration.js.map +1 -0
  124. package/dist/server/services/plan/parser.d.ts +11 -3
  125. package/dist/server/services/plan/parser.d.ts.map +1 -1
  126. package/dist/server/services/plan/parser.js +184 -369
  127. package/dist/server/services/plan/parser.js.map +1 -1
  128. package/dist/server/services/plan/prompt-builder.d.ts +17 -0
  129. package/dist/server/services/plan/prompt-builder.d.ts.map +1 -0
  130. package/dist/server/services/plan/prompt-builder.js +137 -0
  131. package/dist/server/services/plan/prompt-builder.js.map +1 -0
  132. package/dist/server/services/plan/review-gate.d.ts +28 -0
  133. package/dist/server/services/plan/review-gate.d.ts.map +1 -0
  134. package/dist/server/services/plan/review-gate.js +191 -0
  135. package/dist/server/services/plan/review-gate.js.map +1 -0
  136. package/dist/server/services/plan/state-reconciler.d.ts +1 -1
  137. package/dist/server/services/plan/state-reconciler.d.ts.map +1 -1
  138. package/dist/server/services/plan/state-reconciler.js +59 -7
  139. package/dist/server/services/plan/state-reconciler.js.map +1 -1
  140. package/dist/server/services/plan/types.d.ts +68 -0
  141. package/dist/server/services/plan/types.d.ts.map +1 -1
  142. package/dist/server/services/platform-credentials.d.ts +24 -0
  143. package/dist/server/services/platform-credentials.d.ts.map +1 -0
  144. package/dist/server/services/platform-credentials.js +68 -0
  145. package/dist/server/services/platform-credentials.js.map +1 -0
  146. package/dist/server/services/platform.d.ts +1 -31
  147. package/dist/server/services/platform.d.ts.map +1 -1
  148. package/dist/server/services/platform.js +11 -109
  149. package/dist/server/services/platform.js.map +1 -1
  150. package/dist/server/services/terminal/pty-manager.d.ts +7 -97
  151. package/dist/server/services/terminal/pty-manager.d.ts.map +1 -1
  152. package/dist/server/services/terminal/pty-manager.js +53 -266
  153. package/dist/server/services/terminal/pty-manager.js.map +1 -1
  154. package/dist/server/services/terminal/pty-utils.d.ts +57 -0
  155. package/dist/server/services/terminal/pty-utils.d.ts.map +1 -0
  156. package/dist/server/services/terminal/pty-utils.js +141 -0
  157. package/dist/server/services/terminal/pty-utils.js.map +1 -0
  158. package/dist/server/services/websocket/file-definition-handlers.d.ts +4 -0
  159. package/dist/server/services/websocket/file-definition-handlers.d.ts.map +1 -0
  160. package/dist/server/services/websocket/file-definition-handlers.js +153 -0
  161. package/dist/server/services/websocket/file-definition-handlers.js.map +1 -0
  162. package/dist/server/services/websocket/file-explorer-handlers.d.ts.map +1 -1
  163. package/dist/server/services/websocket/file-explorer-handlers.js +52 -391
  164. package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -1
  165. package/dist/server/services/websocket/file-search-handlers.d.ts +5 -0
  166. package/dist/server/services/websocket/file-search-handlers.d.ts.map +1 -0
  167. package/dist/server/services/websocket/file-search-handlers.js +238 -0
  168. package/dist/server/services/websocket/file-search-handlers.js.map +1 -0
  169. package/dist/server/services/websocket/file-utils.js +3 -3
  170. package/dist/server/services/websocket/file-utils.js.map +1 -1
  171. package/dist/server/services/websocket/git-branch-handlers.d.ts +7 -0
  172. package/dist/server/services/websocket/git-branch-handlers.d.ts.map +1 -0
  173. package/dist/server/services/websocket/git-branch-handlers.js +110 -0
  174. package/dist/server/services/websocket/git-branch-handlers.js.map +1 -0
  175. package/dist/server/services/websocket/git-diff-handlers.d.ts +6 -0
  176. package/dist/server/services/websocket/git-diff-handlers.d.ts.map +1 -0
  177. package/dist/server/services/websocket/git-diff-handlers.js +123 -0
  178. package/dist/server/services/websocket/git-diff-handlers.js.map +1 -0
  179. package/dist/server/services/websocket/git-handlers.d.ts +2 -31
  180. package/dist/server/services/websocket/git-handlers.d.ts.map +1 -1
  181. package/dist/server/services/websocket/git-handlers.js +35 -541
  182. package/dist/server/services/websocket/git-handlers.js.map +1 -1
  183. package/dist/server/services/websocket/git-log-handlers.d.ts +6 -0
  184. package/dist/server/services/websocket/git-log-handlers.d.ts.map +1 -0
  185. package/dist/server/services/websocket/git-log-handlers.js +128 -0
  186. package/dist/server/services/websocket/git-log-handlers.js.map +1 -0
  187. package/dist/server/services/websocket/git-pr-handlers.d.ts.map +1 -1
  188. package/dist/server/services/websocket/git-pr-handlers.js +13 -53
  189. package/dist/server/services/websocket/git-pr-handlers.js.map +1 -1
  190. package/dist/server/services/websocket/git-tag-handlers.d.ts +6 -0
  191. package/dist/server/services/websocket/git-tag-handlers.d.ts.map +1 -0
  192. package/dist/server/services/websocket/git-tag-handlers.js +76 -0
  193. package/dist/server/services/websocket/git-tag-handlers.js.map +1 -0
  194. package/dist/server/services/websocket/git-utils.d.ts +43 -0
  195. package/dist/server/services/websocket/git-utils.d.ts.map +1 -0
  196. package/dist/server/services/websocket/git-utils.js +201 -0
  197. package/dist/server/services/websocket/git-utils.js.map +1 -0
  198. package/dist/server/services/websocket/handler.d.ts +2 -0
  199. package/dist/server/services/websocket/handler.d.ts.map +1 -1
  200. package/dist/server/services/websocket/handler.js +37 -112
  201. package/dist/server/services/websocket/handler.js.map +1 -1
  202. package/dist/server/services/websocket/plan-board-handlers.d.ts +11 -0
  203. package/dist/server/services/websocket/plan-board-handlers.d.ts.map +1 -0
  204. package/dist/server/services/websocket/plan-board-handlers.js +218 -0
  205. package/dist/server/services/websocket/plan-board-handlers.js.map +1 -0
  206. package/dist/server/services/websocket/plan-execution-handlers.d.ts +9 -0
  207. package/dist/server/services/websocket/plan-execution-handlers.d.ts.map +1 -0
  208. package/dist/server/services/websocket/plan-execution-handlers.js +142 -0
  209. package/dist/server/services/websocket/plan-execution-handlers.js.map +1 -0
  210. package/dist/server/services/websocket/plan-handlers.d.ts +7 -2
  211. package/dist/server/services/websocket/plan-handlers.d.ts.map +1 -1
  212. package/dist/server/services/websocket/plan-handlers.js +21 -462
  213. package/dist/server/services/websocket/plan-handlers.js.map +1 -1
  214. package/dist/server/services/websocket/plan-helpers.d.ts +19 -0
  215. package/dist/server/services/websocket/plan-helpers.d.ts.map +1 -0
  216. package/dist/server/services/websocket/plan-helpers.js +199 -0
  217. package/dist/server/services/websocket/plan-helpers.js.map +1 -0
  218. package/dist/server/services/websocket/plan-issue-handlers.d.ts +12 -0
  219. package/dist/server/services/websocket/plan-issue-handlers.d.ts.map +1 -0
  220. package/dist/server/services/websocket/plan-issue-handlers.js +162 -0
  221. package/dist/server/services/websocket/plan-issue-handlers.js.map +1 -0
  222. package/dist/server/services/websocket/plan-sprint-handlers.d.ts +7 -0
  223. package/dist/server/services/websocket/plan-sprint-handlers.d.ts.map +1 -0
  224. package/dist/server/services/websocket/plan-sprint-handlers.js +206 -0
  225. package/dist/server/services/websocket/plan-sprint-handlers.js.map +1 -0
  226. package/dist/server/services/websocket/quality-complexity.d.ts +14 -0
  227. package/dist/server/services/websocket/quality-complexity.d.ts.map +1 -0
  228. package/dist/server/services/websocket/quality-complexity.js +262 -0
  229. package/dist/server/services/websocket/quality-complexity.js.map +1 -0
  230. package/dist/server/services/websocket/quality-fix-agent.d.ts +16 -0
  231. package/dist/server/services/websocket/quality-fix-agent.d.ts.map +1 -0
  232. package/dist/server/services/websocket/quality-fix-agent.js +140 -0
  233. package/dist/server/services/websocket/quality-fix-agent.js.map +1 -0
  234. package/dist/server/services/websocket/quality-handlers.d.ts.map +1 -1
  235. package/dist/server/services/websocket/quality-handlers.js +34 -346
  236. package/dist/server/services/websocket/quality-handlers.js.map +1 -1
  237. package/dist/server/services/websocket/quality-linting.d.ts +9 -0
  238. package/dist/server/services/websocket/quality-linting.d.ts.map +1 -0
  239. package/dist/server/services/websocket/quality-linting.js +178 -0
  240. package/dist/server/services/websocket/quality-linting.js.map +1 -0
  241. package/dist/server/services/websocket/quality-review-agent.d.ts +19 -0
  242. package/dist/server/services/websocket/quality-review-agent.d.ts.map +1 -0
  243. package/dist/server/services/websocket/quality-review-agent.js +206 -0
  244. package/dist/server/services/websocket/quality-review-agent.js.map +1 -0
  245. package/dist/server/services/websocket/quality-service.d.ts +3 -51
  246. package/dist/server/services/websocket/quality-service.d.ts.map +1 -1
  247. package/dist/server/services/websocket/quality-service.js +9 -651
  248. package/dist/server/services/websocket/quality-service.js.map +1 -1
  249. package/dist/server/services/websocket/quality-tools.d.ts +23 -0
  250. package/dist/server/services/websocket/quality-tools.d.ts.map +1 -0
  251. package/dist/server/services/websocket/quality-tools.js +208 -0
  252. package/dist/server/services/websocket/quality-tools.js.map +1 -0
  253. package/dist/server/services/websocket/quality-types.d.ts +59 -0
  254. package/dist/server/services/websocket/quality-types.d.ts.map +1 -0
  255. package/dist/server/services/websocket/quality-types.js +101 -0
  256. package/dist/server/services/websocket/quality-types.js.map +1 -0
  257. package/dist/server/services/websocket/session-handlers.d.ts +3 -4
  258. package/dist/server/services/websocket/session-handlers.d.ts.map +1 -1
  259. package/dist/server/services/websocket/session-handlers.js +3 -378
  260. package/dist/server/services/websocket/session-handlers.js.map +1 -1
  261. package/dist/server/services/websocket/session-history.d.ts +4 -0
  262. package/dist/server/services/websocket/session-history.d.ts.map +1 -0
  263. package/dist/server/services/websocket/session-history.js +208 -0
  264. package/dist/server/services/websocket/session-history.js.map +1 -0
  265. package/dist/server/services/websocket/session-initialization.d.ts +5 -0
  266. package/dist/server/services/websocket/session-initialization.d.ts.map +1 -0
  267. package/dist/server/services/websocket/session-initialization.js +163 -0
  268. package/dist/server/services/websocket/session-initialization.js.map +1 -0
  269. package/dist/server/services/websocket/types.d.ts +12 -2
  270. package/dist/server/services/websocket/types.d.ts.map +1 -1
  271. package/package.json +1 -2
  272. package/server/cli/headless/claude-invoker-process.ts +204 -0
  273. package/server/cli/headless/claude-invoker-stall.ts +164 -0
  274. package/server/cli/headless/claude-invoker-stream.ts +353 -0
  275. package/server/cli/headless/claude-invoker-tools.ts +187 -0
  276. package/server/cli/headless/claude-invoker.ts +15 -1092
  277. package/server/cli/headless/haiku-assessments.ts +365 -0
  278. package/server/cli/headless/headless-logger.ts +26 -5
  279. package/server/cli/headless/native-timeout-detector.ts +117 -0
  280. package/server/cli/headless/stall-assessor.ts +65 -618
  281. package/server/cli/headless/types.ts +4 -1
  282. package/server/cli/improvisation-attachments.ts +148 -0
  283. package/server/cli/improvisation-retry.ts +602 -0
  284. package/server/cli/improvisation-session-manager.ts +140 -1349
  285. package/server/cli/improvisation-types.ts +98 -0
  286. package/server/cli/prompt-builders.ts +370 -0
  287. package/server/index.ts +35 -246
  288. package/server/mcp/bouncer-haiku.ts +182 -0
  289. package/server/mcp/bouncer-integration.ts +87 -248
  290. package/server/mcp/security-analysis.ts +217 -0
  291. package/server/mcp/security-audit.ts +1 -1
  292. package/server/mcp/security-patterns.ts +60 -283
  293. package/server/server-setup.ts +114 -0
  294. package/server/services/file-explorer-ops.ts +293 -0
  295. package/server/services/files.ts +20 -532
  296. package/server/services/plan/composer.ts +140 -35
  297. package/server/services/plan/config-installer.ts +187 -0
  298. package/server/services/plan/dependency-resolver.ts +4 -1
  299. package/server/services/plan/executor.ts +281 -488
  300. package/server/services/plan/front-matter.ts +48 -0
  301. package/server/services/plan/output-manager.ts +113 -0
  302. package/server/services/plan/parser-core.ts +406 -0
  303. package/server/services/plan/parser-migration.ts +128 -0
  304. package/server/services/plan/parser.ts +188 -394
  305. package/server/services/plan/prompt-builder.ts +161 -0
  306. package/server/services/plan/review-gate.ts +212 -0
  307. package/server/services/plan/state-reconciler.ts +68 -7
  308. package/server/services/plan/types.ts +101 -1
  309. package/server/services/platform-credentials.ts +83 -0
  310. package/server/services/platform.ts +16 -131
  311. package/server/services/terminal/pty-manager.ts +66 -313
  312. package/server/services/terminal/pty-utils.ts +176 -0
  313. package/server/services/websocket/file-definition-handlers.ts +165 -0
  314. package/server/services/websocket/file-explorer-handlers.ts +37 -452
  315. package/server/services/websocket/file-search-handlers.ts +291 -0
  316. package/server/services/websocket/file-utils.ts +3 -3
  317. package/server/services/websocket/git-branch-handlers.ts +130 -0
  318. package/server/services/websocket/git-diff-handlers.ts +140 -0
  319. package/server/services/websocket/git-handlers.ts +40 -625
  320. package/server/services/websocket/git-log-handlers.ts +149 -0
  321. package/server/services/websocket/git-pr-handlers.ts +17 -62
  322. package/server/services/websocket/git-tag-handlers.ts +91 -0
  323. package/server/services/websocket/git-utils.ts +230 -0
  324. package/server/services/websocket/handler.ts +39 -112
  325. package/server/services/websocket/plan-board-handlers.ts +277 -0
  326. package/server/services/websocket/plan-execution-handlers.ts +184 -0
  327. package/server/services/websocket/plan-handlers.ts +23 -544
  328. package/server/services/websocket/plan-helpers.ts +215 -0
  329. package/server/services/websocket/plan-issue-handlers.ts +204 -0
  330. package/server/services/websocket/plan-sprint-handlers.ts +252 -0
  331. package/server/services/websocket/quality-complexity.ts +294 -0
  332. package/server/services/websocket/quality-fix-agent.ts +181 -0
  333. package/server/services/websocket/quality-handlers.ts +36 -404
  334. package/server/services/websocket/quality-linting.ts +187 -0
  335. package/server/services/websocket/quality-review-agent.ts +246 -0
  336. package/server/services/websocket/quality-service.ts +11 -762
  337. package/server/services/websocket/quality-tools.ts +209 -0
  338. package/server/services/websocket/quality-types.ts +169 -0
  339. package/server/services/websocket/session-handlers.ts +5 -437
  340. package/server/services/websocket/session-history.ts +222 -0
  341. package/server/services/websocket/session-initialization.ts +209 -0
  342. package/server/services/websocket/types.ts +46 -2
@@ -0,0 +1,294 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file for details.
3
+
4
+ import { existsSync } from 'node:fs';
5
+ import { extname, join, relative } from 'node:path';
6
+ import { runCommand, type SourceFile } from './quality-tools.js';
7
+ import { biomeDiagToFinding, type Ecosystem, FUNCTION_LENGTH_THRESHOLD, isBiomeComplexityDiagnostic, isEslintComplexityRule, type QualityFinding } from './quality-types.js';
8
+
9
+ // ============================================================================
10
+ // Function Length Analysis
11
+ // ============================================================================
12
+
13
+ interface FunctionInfo {
14
+ name: string;
15
+ file: string;
16
+ startLine: number;
17
+ lines: number;
18
+ }
19
+
20
+ const JS_FUNC_PATTERN = /^(\s*)(export\s+)?(async\s+)?function\s+(\w+)|^(\s*)(export\s+)?(const|let|var)\s+(\w+)\s*=\s*(async\s+)?\(|^(\s*)(public|private|protected)?\s*(async\s+)?(\w+)\s*\(/;
21
+
22
+ function countBraceDeltas(line: string): number {
23
+ let delta = 0;
24
+ for (const ch of line) {
25
+ if (ch === '{') delta++;
26
+ else if (ch === '}') delta--;
27
+ }
28
+ return delta;
29
+ }
30
+
31
+ function matchJsFuncStart(line: string): { name: string; indent: number } | null {
32
+ const match = JS_FUNC_PATTERN.exec(line);
33
+ if (!match) return null;
34
+ const name = match[4] || match[8] || match[13] || 'anonymous';
35
+ const indent = (match[1] || match[5] || match[10] || '').length;
36
+ return { name, indent };
37
+ }
38
+
39
+ function extractJsFunctions(file: SourceFile): FunctionInfo[] {
40
+ const functions: FunctionInfo[] = [];
41
+ const lines = file.content.split('\n');
42
+ let braceDepth = 0;
43
+ let currentFunc: { name: string; startLine: number; indent: number } | null = null;
44
+ let funcStartBraceDepth = 0;
45
+
46
+ for (let i = 0; i < lines.length; i++) {
47
+ if (!currentFunc) {
48
+ const funcStart = matchJsFuncStart(lines[i]);
49
+ if (funcStart) {
50
+ currentFunc = { name: funcStart.name, startLine: i + 1, indent: funcStart.indent };
51
+ funcStartBraceDepth = braceDepth;
52
+ }
53
+ }
54
+
55
+ braceDepth += countBraceDeltas(lines[i]);
56
+
57
+ if (currentFunc && braceDepth <= funcStartBraceDepth && i > currentFunc.startLine - 1) {
58
+ functions.push({
59
+ name: currentFunc.name,
60
+ file: file.relativePath,
61
+ startLine: currentFunc.startLine,
62
+ lines: i + 1 - currentFunc.startLine + 1,
63
+ });
64
+ currentFunc = null;
65
+ }
66
+ }
67
+
68
+ return functions;
69
+ }
70
+
71
+ function extractPyFunctions(file: SourceFile): FunctionInfo[] {
72
+ const functions: FunctionInfo[] = [];
73
+ const lines = file.content.split('\n');
74
+ const defPattern = /^(\s*)(async\s+)?def\s+(\w+)/;
75
+ let currentFunc: { name: string; startLine: number; indent: number } | null = null;
76
+
77
+ for (let i = 0; i < lines.length; i++) {
78
+ const match = defPattern.exec(lines[i]);
79
+ if (match) {
80
+ if (currentFunc) {
81
+ functions.push({
82
+ name: currentFunc.name,
83
+ file: file.relativePath,
84
+ startLine: currentFunc.startLine,
85
+ lines: i - currentFunc.startLine + 1,
86
+ });
87
+ }
88
+ currentFunc = { name: match[3], startLine: i + 1, indent: match[1].length };
89
+ } else if (currentFunc && lines[i].trim() && !lines[i].startsWith(' '.repeat(currentFunc.indent + 1)) && !lines[i].startsWith('\t')) {
90
+ functions.push({
91
+ name: currentFunc.name,
92
+ file: file.relativePath,
93
+ startLine: currentFunc.startLine,
94
+ lines: i - currentFunc.startLine + 1,
95
+ });
96
+ currentFunc = null;
97
+ }
98
+ }
99
+ if (currentFunc) {
100
+ functions.push({
101
+ name: currentFunc.name,
102
+ file: file.relativePath,
103
+ startLine: currentFunc.startLine,
104
+ lines: lines.length - currentFunc.startLine + 1,
105
+ });
106
+ }
107
+
108
+ return functions;
109
+ }
110
+
111
+ function extractFunctions(file: SourceFile): FunctionInfo[] {
112
+ const ext = extname(file.path).toLowerCase();
113
+ if (['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'].includes(ext)) return extractJsFunctions(file);
114
+ if (['.py', '.pyi'].includes(ext)) return extractPyFunctions(file);
115
+ return [];
116
+ }
117
+
118
+ export function analyzeFunctionLength(files: SourceFile[]): { score: number; findings: QualityFinding[]; issueCount: number } {
119
+ const allFunctions: FunctionInfo[] = [];
120
+ for (const file of files) {
121
+ allFunctions.push(...extractFunctions(file));
122
+ }
123
+
124
+ if (allFunctions.length === 0) return { score: 100, findings: [], issueCount: 0 };
125
+
126
+ const findings: QualityFinding[] = [];
127
+ let totalScore = 0;
128
+
129
+ for (const func of allFunctions) {
130
+ const ratio = Math.max(1, func.lines / FUNCTION_LENGTH_THRESHOLD);
131
+ const funcScore = 100 / ratio ** 1.5;
132
+ totalScore += funcScore;
133
+
134
+ if (func.lines > FUNCTION_LENGTH_THRESHOLD) {
135
+ findings.push({
136
+ severity: func.lines > FUNCTION_LENGTH_THRESHOLD * 3 ? 'high' : func.lines > FUNCTION_LENGTH_THRESHOLD * 2 ? 'medium' : 'low',
137
+ category: 'function-length',
138
+ file: func.file,
139
+ line: func.startLine,
140
+ title: `${func.name}() has ${func.lines} lines (threshold: ${FUNCTION_LENGTH_THRESHOLD})`,
141
+ description: `Function "${func.name}" exceeds the recommended length by ${func.lines - FUNCTION_LENGTH_THRESHOLD} lines.`,
142
+ });
143
+ }
144
+ }
145
+
146
+ const score = Math.round(totalScore / allFunctions.length);
147
+ return { score: Math.min(100, score), findings: findings.slice(0, 50), issueCount: findings.length };
148
+ }
149
+
150
+ // ============================================================================
151
+ // Complexity Analysis (Biome, ESLint, radon)
152
+ // ============================================================================
153
+
154
+ function computeComplexityScore(findings: QualityFinding[]): number {
155
+ let penalty = 0;
156
+ for (const f of findings) {
157
+ if (f.severity === 'high' || f.severity === 'critical') penalty += 8;
158
+ else if (f.severity === 'medium') penalty += 5;
159
+ else penalty += 3;
160
+ }
161
+ return Math.max(0, 100 - penalty);
162
+ }
163
+
164
+ async function complexityFromBiome(dirPath: string): Promise<QualityFinding[] | null> {
165
+ const hasBiomeConfig = existsSync(join(dirPath, 'biome.json')) || existsSync(join(dirPath, 'biome.jsonc'));
166
+ if (!hasBiomeConfig) return null;
167
+
168
+ const result = await runCommand('npx', ['@biomejs/biome', 'lint', '--reporter=json', '.'], dirPath);
169
+ if (result.exitCode > 1) return null;
170
+
171
+ try {
172
+ const parsed = JSON.parse(result.stdout);
173
+ if (!parsed.diagnostics) return [];
174
+ return parsed.diagnostics
175
+ .filter(isBiomeComplexityDiagnostic)
176
+ .map((d: Record<string, unknown>) => biomeDiagToFinding(d, 'complexity'));
177
+ } catch {
178
+ return null;
179
+ }
180
+ }
181
+
182
+ async function complexityFromEslint(dirPath: string): Promise<QualityFinding[] | null> {
183
+ const result = await runCommand('npx', ['eslint', '--format=json', '.'], dirPath);
184
+ if (result.exitCode > 1 && !result.stdout.trim().startsWith('[')) return null;
185
+
186
+ const findings: QualityFinding[] = [];
187
+ try {
188
+ const parsed = JSON.parse(result.stdout);
189
+ for (const file of parsed) {
190
+ for (const msg of file.messages || []) {
191
+ if (!isEslintComplexityRule(msg.ruleId)) continue;
192
+ findings.push({
193
+ severity: msg.severity === 2 ? 'high' : 'medium',
194
+ category: 'complexity',
195
+ file: relative(dirPath, file.filePath),
196
+ line: msg.line ?? null,
197
+ title: msg.ruleId || 'complexity',
198
+ description: msg.message,
199
+ });
200
+ }
201
+ }
202
+ } catch {
203
+ return null;
204
+ }
205
+
206
+ return findings;
207
+ }
208
+
209
+ function radonFuncToFinding(filePath: string, func: Record<string, unknown>): QualityFinding | null {
210
+ const cc = func.complexity as number;
211
+ if (cc <= 10) return null;
212
+ return {
213
+ severity: cc > 20 ? 'high' : cc > 15 ? 'medium' : 'low',
214
+ category: 'complexity',
215
+ file: filePath,
216
+ line: (func.lineno as number) ?? null,
217
+ title: `${func.name}() has cyclomatic complexity ${cc}`,
218
+ description: `Complexity of ${cc} exceeds threshold of 10. Rank: ${func.rank}. Consider refactoring.`,
219
+ };
220
+ }
221
+
222
+ async function complexityFromRadon(dirPath: string): Promise<QualityFinding[] | null> {
223
+ const result = await runCommand('radon', ['cc', '--json', '.'], dirPath);
224
+ if (result.exitCode !== 0 && !result.stdout.trim().startsWith('{')) return null;
225
+
226
+ try {
227
+ const parsed = JSON.parse(result.stdout) as Record<string, Array<Record<string, unknown>>>;
228
+ const findings: QualityFinding[] = [];
229
+ for (const [filePath, functions] of Object.entries(parsed)) {
230
+ for (const func of functions) {
231
+ const finding = radonFuncToFinding(filePath, func);
232
+ if (finding) findings.push(finding);
233
+ }
234
+ }
235
+ return findings;
236
+ } catch {
237
+ return null;
238
+ }
239
+ }
240
+
241
+ async function analyzeNodeComplexity(
242
+ dirPath: string,
243
+ installed: Set<string> | null,
244
+ ): Promise<QualityFinding[] | null> {
245
+ const hasCapableTool = !installed || installed.has('biome') || installed.has('eslint');
246
+ if (!hasCapableTool) return null;
247
+
248
+ const hasBiomeConfig = existsSync(join(dirPath, 'biome.json')) || existsSync(join(dirPath, 'biome.jsonc'));
249
+ if (hasBiomeConfig) {
250
+ const findings = await complexityFromBiome(dirPath);
251
+ if (findings) return findings;
252
+ }
253
+ return complexityFromEslint(dirPath);
254
+ }
255
+
256
+ async function analyzePythonComplexity(
257
+ dirPath: string,
258
+ installed: Set<string> | null,
259
+ ): Promise<QualityFinding[] | null> {
260
+ const hasRadon = !installed || installed.has('radon');
261
+ if (!hasRadon) return null;
262
+ return complexityFromRadon(dirPath);
263
+ }
264
+
265
+ export async function analyzeComplexity(
266
+ dirPath: string,
267
+ ecosystems: Ecosystem[],
268
+ installedToolNames?: string[],
269
+ ): Promise<{ score: number; findings: QualityFinding[]; issueCount: number; available: boolean }> {
270
+ const allFindings: QualityFinding[] = [];
271
+ const installed = installedToolNames ? new Set(installedToolNames) : null;
272
+ let canAnalyze = false;
273
+
274
+ for (const ecosystem of ecosystems) {
275
+ const analyze = ecosystem === 'node' ? analyzeNodeComplexity : ecosystem === 'python' ? analyzePythonComplexity : null;
276
+ if (!analyze) continue;
277
+ const findings = await analyze(dirPath, installed);
278
+ if (findings) {
279
+ canAnalyze = true;
280
+ allFindings.push(...findings);
281
+ }
282
+ }
283
+
284
+ if (!canAnalyze) {
285
+ return { score: 0, findings: [], issueCount: 0, available: false };
286
+ }
287
+
288
+ return {
289
+ score: allFindings.length > 0 ? computeComplexityScore(allFindings) : 100,
290
+ findings: allFindings.slice(0, 50),
291
+ issueCount: allFindings.length,
292
+ available: true,
293
+ };
294
+ }
@@ -0,0 +1,181 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file for details.
3
+
4
+ /**
5
+ * Quality Fix Agent — AI-powered issue fixing using Claude Code headless runner.
6
+ *
7
+ * Builds the fix prompt, runs the agent, re-scans, and persists updated results.
8
+ */
9
+
10
+ import { runWithFileLogger } from '../../cli/headless/headless-logger.js';
11
+ import { HeadlessRunner } from '../../cli/headless/index.js';
12
+ import type { ToolUseEvent } from '../../cli/headless/types.js';
13
+ import type { HandlerContext } from './handler-context.js';
14
+ import type { QualityPersistence } from './quality-persistence.js';
15
+ import { detectTools, runQualityScan } from './quality-service.js';
16
+ import type { WSContext } from './types.js';
17
+
18
+ // ── Types ─────────────────────────────────────────────────────
19
+
20
+ export interface FindingForFix {
21
+ severity: string;
22
+ category: string;
23
+ file: string;
24
+ line: number | null;
25
+ title: string;
26
+ description: string;
27
+ suggestion?: string;
28
+ }
29
+
30
+ // ── Progress callback ─────────────────────────────────────────
31
+
32
+ const TOOL_MESSAGES: Record<string, string> = {
33
+ Read: 'Reading files to understand issues...',
34
+ Edit: 'Applying fixes...',
35
+ Write: 'Writing fixes...',
36
+ Grep: 'Searching for related code...',
37
+ Bash: 'Running verification...',
38
+ };
39
+
40
+ export function createToolProgressCallback(ctx: HandlerContext, ws: WSContext, reportPath: string) {
41
+ const seenTools = new Set<string>();
42
+ return (event: ToolUseEvent) => {
43
+ if (event.type === 'tool_start' && event.toolName && !seenTools.has(event.toolName)) {
44
+ seenTools.add(event.toolName);
45
+ const message = TOOL_MESSAGES[event.toolName];
46
+ if (message) {
47
+ ctx.send(ws, { type: 'qualityFixProgress', data: { path: reportPath, message } });
48
+ }
49
+ }
50
+ if (event.type === 'tool_complete' && event.toolName === 'Edit' && event.completeInput?.file_path) {
51
+ ctx.send(ws, {
52
+ type: 'qualityFixProgress',
53
+ data: { path: reportPath, message: `Fixed ${String(event.completeInput.file_path).split('/').slice(-2).join('/')}` },
54
+ });
55
+ }
56
+ };
57
+ }
58
+
59
+ // ── Prompt ────────────────────────────────────────────────────
60
+
61
+ function buildFixPrompt(findings: FindingForFix[], section?: string): string {
62
+ const filtered = section ? findings.filter((f) => f.category === section) : findings;
63
+ const sorted = filtered.sort((a, b) => {
64
+ const order: Record<string, number> = { critical: 0, high: 1, medium: 2, low: 3 };
65
+ return (order[a.severity] ?? 4) - (order[b.severity] ?? 4);
66
+ });
67
+
68
+ const issueList = sorted.slice(0, 30).map((f, i) => {
69
+ const loc = f.line ? `${f.file}:${f.line}` : f.file;
70
+ const parts = [`${i + 1}. [${f.severity.toUpperCase()}] ${loc} — ${f.title}`];
71
+ if (f.description) parts.push(` ${f.description}`);
72
+ if (f.suggestion) parts.push(` Suggestion: ${f.suggestion}`);
73
+ return parts.join('\n');
74
+ }).join('\n\n');
75
+
76
+ return `You are a code quality fix agent. Fix the following quality issues in the codebase.
77
+
78
+ ## Issues to Fix (${sorted.length} total, showing top ${Math.min(30, sorted.length)})
79
+
80
+ ${issueList}
81
+
82
+ ## Rules
83
+
84
+ - Fix each issue by editing the relevant file at the specified location.
85
+ - For complexity issues: refactor into smaller functions. For long files: split or extract modules. For long functions: break into smaller functions.
86
+ - For security issues: apply the suggested fix or use secure coding best practices.
87
+ - For bugs: fix the root cause, not just the symptom.
88
+ - For linting/formatting: apply the standard for the project.
89
+ - Do NOT introduce new issues. Make minimal, focused changes.
90
+ - After fixing, verify the changes compile/pass linting if tools are available.
91
+ - Work through the issues systematically from most to least severe.`;
92
+ }
93
+
94
+ // ── Handler ───────────────────────────────────────────────────
95
+
96
+ const activeFixes = new Set<string>();
97
+
98
+ export async function handleFixIssues(
99
+ ctx: HandlerContext,
100
+ ws: WSContext,
101
+ reportPath: string,
102
+ dirPath: string,
103
+ workingDir: string,
104
+ section: string | undefined,
105
+ findings: FindingForFix[],
106
+ getPersistence: (dir: string) => QualityPersistence,
107
+ ): Promise<void> {
108
+ if (activeFixes.has(dirPath)) {
109
+ ctx.send(ws, {
110
+ type: 'qualityError',
111
+ data: { path: reportPath, error: 'A fix operation is already running for this directory.' },
112
+ });
113
+ return;
114
+ }
115
+
116
+ if (findings.length === 0) {
117
+ ctx.send(ws, {
118
+ type: 'qualityError',
119
+ data: { path: reportPath, error: 'No findings to fix.' },
120
+ });
121
+ return;
122
+ }
123
+
124
+ activeFixes.add(dirPath);
125
+ try {
126
+ ctx.send(ws, {
127
+ type: 'qualityFixProgress',
128
+ data: { path: reportPath, message: 'Starting Claude Code to fix issues...' },
129
+ });
130
+
131
+ const prompt = buildFixPrompt(findings, section);
132
+
133
+ const runner = new HeadlessRunner({
134
+ workingDir: dirPath,
135
+ directPrompt: prompt,
136
+ stallWarningMs: 120_000,
137
+ stallKillMs: 600_000,
138
+ stallHardCapMs: 900_000,
139
+ toolUseCallback: createToolProgressCallback(ctx, ws, reportPath),
140
+ });
141
+
142
+ await runWithFileLogger('code-review-fix', () => runner.run());
143
+
144
+ ctx.send(ws, {
145
+ type: 'qualityFixProgress',
146
+ data: { path: reportPath, message: 'Fixes applied. Re-running quality checks...' },
147
+ });
148
+
149
+ // Re-run quality scan after fixing
150
+ const { tools: detectedTools } = await detectTools(dirPath);
151
+ const installedToolNames = detectedTools.filter((t) => t.installed).map((t) => t.name);
152
+
153
+ const results = await runQualityScan(dirPath, (progress) => {
154
+ ctx.send(ws, {
155
+ type: 'qualityScanProgress',
156
+ data: { path: reportPath, progress },
157
+ });
158
+ }, installedToolNames);
159
+
160
+ ctx.send(ws, {
161
+ type: 'qualityFixComplete',
162
+ data: { path: reportPath, results },
163
+ });
164
+
165
+ // Persist
166
+ try {
167
+ const persistence = getPersistence(workingDir);
168
+ persistence.saveReport(reportPath, results);
169
+ persistence.appendHistory(results, reportPath);
170
+ } catch {
171
+ // Persistence failure should not break the fix flow
172
+ }
173
+ } catch (error) {
174
+ ctx.send(ws, {
175
+ type: 'qualityError',
176
+ data: { path: reportPath, error: error instanceof Error ? error.message : String(error) },
177
+ });
178
+ } finally {
179
+ activeFixes.delete(dirPath);
180
+ }
181
+ }