mstro-app 0.4.52 → 0.5.1

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 (590) hide show
  1. package/LICENSE +129 -190
  2. package/PRIVACY.md +3 -3
  3. package/README.md +15 -6
  4. package/bin/commands/config.js +0 -1
  5. package/bin/mstro.js +1 -2
  6. package/bin/postinstall.js +0 -1
  7. package/dist/server/cli/headless/claude-invoker-process.d.ts.map +1 -1
  8. package/dist/server/cli/headless/claude-invoker-process.js +0 -1
  9. package/dist/server/cli/headless/claude-invoker-process.js.map +1 -1
  10. package/dist/server/cli/headless/claude-invoker-stall.d.ts.map +1 -1
  11. package/dist/server/cli/headless/claude-invoker-stall.js +7 -3
  12. package/dist/server/cli/headless/claude-invoker-stall.js.map +1 -1
  13. package/dist/server/cli/headless/claude-invoker-stream.d.ts.map +1 -1
  14. package/dist/server/cli/headless/claude-invoker-stream.js +0 -1
  15. package/dist/server/cli/headless/claude-invoker-stream.js.map +1 -1
  16. package/dist/server/cli/headless/claude-invoker-tools.d.ts.map +1 -1
  17. package/dist/server/cli/headless/claude-invoker-tools.js +0 -1
  18. package/dist/server/cli/headless/claude-invoker-tools.js.map +1 -1
  19. package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -1
  20. package/dist/server/cli/headless/claude-invoker.js +1 -2
  21. package/dist/server/cli/headless/claude-invoker.js.map +1 -1
  22. package/dist/server/cli/headless/haiku-assessments.d.ts.map +1 -1
  23. package/dist/server/cli/headless/haiku-assessments.js +0 -1
  24. package/dist/server/cli/headless/haiku-assessments.js.map +1 -1
  25. package/dist/server/cli/headless/headless-logger.d.ts.map +1 -1
  26. package/dist/server/cli/headless/headless-logger.js +0 -1
  27. package/dist/server/cli/headless/headless-logger.js.map +1 -1
  28. package/dist/server/cli/headless/index.d.ts.map +1 -1
  29. package/dist/server/cli/headless/index.js +0 -1
  30. package/dist/server/cli/headless/index.js.map +1 -1
  31. package/dist/server/cli/headless/native-timeout-detector.d.ts.map +1 -1
  32. package/dist/server/cli/headless/native-timeout-detector.js +0 -1
  33. package/dist/server/cli/headless/native-timeout-detector.js.map +1 -1
  34. package/dist/server/cli/headless/output-utils.d.ts.map +1 -1
  35. package/dist/server/cli/headless/output-utils.js +0 -1
  36. package/dist/server/cli/headless/output-utils.js.map +1 -1
  37. package/dist/server/cli/headless/prompt-utils.d.ts.map +1 -1
  38. package/dist/server/cli/headless/prompt-utils.js +0 -1
  39. package/dist/server/cli/headless/prompt-utils.js.map +1 -1
  40. package/dist/server/cli/headless/resilient-runner.d.ts.map +1 -1
  41. package/dist/server/cli/headless/resilient-runner.js +0 -1
  42. package/dist/server/cli/headless/resilient-runner.js.map +1 -1
  43. package/dist/server/cli/headless/retry-strategies.d.ts.map +1 -1
  44. package/dist/server/cli/headless/retry-strategies.js +0 -1
  45. package/dist/server/cli/headless/retry-strategies.js.map +1 -1
  46. package/dist/server/cli/headless/runner.d.ts.map +1 -1
  47. package/dist/server/cli/headless/runner.js +63 -68
  48. package/dist/server/cli/headless/runner.js.map +1 -1
  49. package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
  50. package/dist/server/cli/headless/stall-assessor.js +9 -5
  51. package/dist/server/cli/headless/stall-assessor.js.map +1 -1
  52. package/dist/server/cli/headless/tool-watchdog.d.ts.map +1 -1
  53. package/dist/server/cli/headless/tool-watchdog.js +0 -1
  54. package/dist/server/cli/headless/tool-watchdog.js.map +1 -1
  55. package/dist/server/cli/headless/types.d.ts.map +1 -1
  56. package/dist/server/cli/headless/types.js +0 -1
  57. package/dist/server/cli/headless/types.js.map +1 -1
  58. package/dist/server/cli/improvisation-attachments.d.ts.map +1 -1
  59. package/dist/server/cli/improvisation-attachments.js +0 -1
  60. package/dist/server/cli/improvisation-attachments.js.map +1 -1
  61. package/dist/server/cli/improvisation-history-store.d.ts +16 -0
  62. package/dist/server/cli/improvisation-history-store.d.ts.map +1 -0
  63. package/dist/server/cli/improvisation-history-store.js +51 -0
  64. package/dist/server/cli/improvisation-history-store.js.map +1 -0
  65. package/dist/server/cli/improvisation-movements.d.ts +31 -0
  66. package/dist/server/cli/improvisation-movements.d.ts.map +1 -0
  67. package/dist/server/cli/improvisation-movements.js +92 -0
  68. package/dist/server/cli/improvisation-movements.js.map +1 -0
  69. package/dist/server/cli/improvisation-output-queue.d.ts +13 -0
  70. package/dist/server/cli/improvisation-output-queue.d.ts.map +1 -0
  71. package/dist/server/cli/improvisation-output-queue.js +39 -0
  72. package/dist/server/cli/improvisation-output-queue.js.map +1 -0
  73. package/dist/server/cli/improvisation-retry.d.ts +21 -51
  74. package/dist/server/cli/improvisation-retry.d.ts.map +1 -1
  75. package/dist/server/cli/improvisation-retry.js +18 -434
  76. package/dist/server/cli/improvisation-retry.js.map +1 -1
  77. package/dist/server/cli/improvisation-session-manager.d.ts +10 -8
  78. package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
  79. package/dist/server/cli/improvisation-session-manager.js +53 -149
  80. package/dist/server/cli/improvisation-session-manager.js.map +1 -1
  81. package/dist/server/cli/improvisation-types.d.ts.map +1 -1
  82. package/dist/server/cli/improvisation-types.js +0 -1
  83. package/dist/server/cli/improvisation-types.js.map +1 -1
  84. package/dist/server/cli/retry/retry-best-result.d.ts +4 -0
  85. package/dist/server/cli/retry/retry-best-result.d.ts.map +1 -0
  86. package/dist/server/cli/retry/retry-best-result.js +60 -0
  87. package/dist/server/cli/retry/retry-best-result.js.map +1 -0
  88. package/dist/server/cli/retry/retry-context-loss.d.ts +6 -0
  89. package/dist/server/cli/retry/retry-context-loss.d.ts.map +1 -0
  90. package/dist/server/cli/retry/retry-context-loss.js +67 -0
  91. package/dist/server/cli/retry/retry-context-loss.js.map +1 -0
  92. package/dist/server/cli/retry/retry-premature-completion.d.ts +5 -0
  93. package/dist/server/cli/retry/retry-premature-completion.d.ts.map +1 -0
  94. package/dist/server/cli/retry/retry-premature-completion.js +80 -0
  95. package/dist/server/cli/retry/retry-premature-completion.js.map +1 -0
  96. package/dist/server/cli/retry/retry-recovery-strategies.d.ts +13 -0
  97. package/dist/server/cli/retry/retry-recovery-strategies.d.ts.map +1 -0
  98. package/dist/server/cli/retry/retry-recovery-strategies.js +165 -0
  99. package/dist/server/cli/retry/retry-recovery-strategies.js.map +1 -0
  100. package/dist/server/cli/retry/retry-resume-strategy.d.ts +12 -0
  101. package/dist/server/cli/retry/retry-resume-strategy.d.ts.map +1 -0
  102. package/dist/server/cli/retry/retry-resume-strategy.js +21 -0
  103. package/dist/server/cli/retry/retry-resume-strategy.js.map +1 -0
  104. package/dist/server/cli/retry/retry-runner-factory.d.ts +11 -0
  105. package/dist/server/cli/retry/retry-runner-factory.d.ts.map +1 -0
  106. package/dist/server/cli/retry/retry-runner-factory.js +59 -0
  107. package/dist/server/cli/retry/retry-runner-factory.js.map +1 -0
  108. package/dist/server/cli/retry/retry-tool-results.d.ts +9 -0
  109. package/dist/server/cli/retry/retry-tool-results.d.ts.map +1 -0
  110. package/dist/server/cli/retry/retry-tool-results.js +23 -0
  111. package/dist/server/cli/retry/retry-tool-results.js.map +1 -0
  112. package/dist/server/cli/retry/retry-types.d.ts +30 -0
  113. package/dist/server/cli/retry/retry-types.d.ts.map +1 -0
  114. package/dist/server/cli/retry/retry-types.js +3 -0
  115. package/dist/server/cli/retry/retry-types.js.map +1 -0
  116. package/dist/server/index.js +21 -110
  117. package/dist/server/index.js.map +1 -1
  118. package/dist/server/mcp/bouncer-cli.js +0 -1
  119. package/dist/server/mcp/bouncer-cli.js.map +1 -1
  120. package/dist/server/mcp/bouncer-haiku.d.ts.map +1 -1
  121. package/dist/server/mcp/bouncer-haiku.js +0 -1
  122. package/dist/server/mcp/bouncer-haiku.js.map +1 -1
  123. package/dist/server/mcp/bouncer-integration.d.ts.map +1 -1
  124. package/dist/server/mcp/bouncer-integration.js +0 -1
  125. package/dist/server/mcp/bouncer-integration.js.map +1 -1
  126. package/dist/server/mcp/security-analysis.d.ts.map +1 -1
  127. package/dist/server/mcp/security-analysis.js +0 -1
  128. package/dist/server/mcp/security-analysis.js.map +1 -1
  129. package/dist/server/mcp/security-audit.d.ts.map +1 -1
  130. package/dist/server/mcp/security-audit.js +0 -1
  131. package/dist/server/mcp/security-audit.js.map +1 -1
  132. package/dist/server/mcp/security-patterns.d.ts.map +1 -1
  133. package/dist/server/mcp/security-patterns.js +0 -1
  134. package/dist/server/mcp/security-patterns.js.map +1 -1
  135. package/dist/server/mcp/server.js +0 -1
  136. package/dist/server/mcp/server.js.map +1 -1
  137. package/dist/server/routes/files.d.ts.map +1 -1
  138. package/dist/server/routes/files.js +0 -1
  139. package/dist/server/routes/files.js.map +1 -1
  140. package/dist/server/routes/improvise.d.ts.map +1 -1
  141. package/dist/server/routes/improvise.js +0 -1
  142. package/dist/server/routes/improvise.js.map +1 -1
  143. package/dist/server/routes/index.d.ts.map +1 -1
  144. package/dist/server/routes/index.js +0 -1
  145. package/dist/server/routes/index.js.map +1 -1
  146. package/dist/server/routes/instances.d.ts.map +1 -1
  147. package/dist/server/routes/instances.js +0 -1
  148. package/dist/server/routes/instances.js.map +1 -1
  149. package/dist/server/routes/notifications.d.ts.map +1 -1
  150. package/dist/server/routes/notifications.js +0 -1
  151. package/dist/server/routes/notifications.js.map +1 -1
  152. package/dist/server/server-setup.d.ts +16 -1
  153. package/dist/server/server-setup.d.ts.map +1 -1
  154. package/dist/server/server-setup.js +107 -1
  155. package/dist/server/server-setup.js.map +1 -1
  156. package/dist/server/services/analytics.d.ts.map +1 -1
  157. package/dist/server/services/analytics.js +0 -1
  158. package/dist/server/services/analytics.js.map +1 -1
  159. package/dist/server/services/auth.d.ts.map +1 -1
  160. package/dist/server/services/auth.js +0 -1
  161. package/dist/server/services/auth.js.map +1 -1
  162. package/dist/server/services/client-id.d.ts.map +1 -1
  163. package/dist/server/services/client-id.js +0 -1
  164. package/dist/server/services/client-id.js.map +1 -1
  165. package/dist/server/services/file-explorer-ops.d.ts.map +1 -1
  166. package/dist/server/services/file-explorer-ops.js +0 -1
  167. package/dist/server/services/file-explorer-ops.js.map +1 -1
  168. package/dist/server/services/files.d.ts.map +1 -1
  169. package/dist/server/services/files.js +0 -1
  170. package/dist/server/services/files.js.map +1 -1
  171. package/dist/server/services/instances.d.ts.map +1 -1
  172. package/dist/server/services/instances.js +0 -1
  173. package/dist/server/services/instances.js.map +1 -1
  174. package/dist/server/services/pathUtils.d.ts.map +1 -1
  175. package/dist/server/services/pathUtils.js +0 -1
  176. package/dist/server/services/pathUtils.js.map +1 -1
  177. package/dist/server/services/plan/agent-loader.d.ts.map +1 -1
  178. package/dist/server/services/plan/agent-loader.js +0 -1
  179. package/dist/server/services/plan/agent-loader.js.map +1 -1
  180. package/dist/server/services/plan/board-config.d.ts +21 -0
  181. package/dist/server/services/plan/board-config.d.ts.map +1 -0
  182. package/dist/server/services/plan/board-config.js +111 -0
  183. package/dist/server/services/plan/board-config.js.map +1 -0
  184. package/dist/server/services/plan/composer.d.ts +1 -1
  185. package/dist/server/services/plan/composer.d.ts.map +1 -1
  186. package/dist/server/services/plan/composer.js +7 -6
  187. package/dist/server/services/plan/composer.js.map +1 -1
  188. package/dist/server/services/plan/config-installer.d.ts.map +1 -1
  189. package/dist/server/services/plan/config-installer.js +0 -1
  190. package/dist/server/services/plan/config-installer.js.map +1 -1
  191. package/dist/server/services/plan/dependency-resolver.d.ts.map +1 -1
  192. package/dist/server/services/plan/dependency-resolver.js +0 -1
  193. package/dist/server/services/plan/dependency-resolver.js.map +1 -1
  194. package/dist/server/services/plan/executor.d.ts +48 -48
  195. package/dist/server/services/plan/executor.d.ts.map +1 -1
  196. package/dist/server/services/plan/executor.js +202 -458
  197. package/dist/server/services/plan/executor.js.map +1 -1
  198. package/dist/server/services/plan/front-matter.d.ts.map +1 -1
  199. package/dist/server/services/plan/front-matter.js +0 -1
  200. package/dist/server/services/plan/front-matter.js.map +1 -1
  201. package/dist/server/services/plan/issue-classification.d.ts.map +1 -1
  202. package/dist/server/services/plan/issue-classification.js +0 -1
  203. package/dist/server/services/plan/issue-classification.js.map +1 -1
  204. package/dist/server/services/plan/issue-loader.d.ts +16 -0
  205. package/dist/server/services/plan/issue-loader.d.ts.map +1 -0
  206. package/dist/server/services/plan/issue-loader.js +45 -0
  207. package/dist/server/services/plan/issue-loader.js.map +1 -0
  208. package/dist/server/services/plan/issue-prompt-builder.d.ts.map +1 -1
  209. package/dist/server/services/plan/issue-prompt-builder.js +0 -1
  210. package/dist/server/services/plan/issue-prompt-builder.js.map +1 -1
  211. package/dist/server/services/plan/issue-retry.d.ts +3 -1
  212. package/dist/server/services/plan/issue-retry.d.ts.map +1 -1
  213. package/dist/server/services/plan/issue-retry.js +2 -1
  214. package/dist/server/services/plan/issue-retry.js.map +1 -1
  215. package/dist/server/services/plan/issue-writer.d.ts +34 -0
  216. package/dist/server/services/plan/issue-writer.d.ts.map +1 -0
  217. package/dist/server/services/plan/issue-writer.js +109 -0
  218. package/dist/server/services/plan/issue-writer.js.map +1 -0
  219. package/dist/server/services/plan/output-manager.js +2 -2
  220. package/dist/server/services/plan/output-manager.js.map +1 -1
  221. package/dist/server/services/plan/parser-core.d.ts.map +1 -1
  222. package/dist/server/services/plan/parser-core.js +0 -1
  223. package/dist/server/services/plan/parser-core.js.map +1 -1
  224. package/dist/server/services/plan/parser-migration.d.ts.map +1 -1
  225. package/dist/server/services/plan/parser-migration.js +0 -1
  226. package/dist/server/services/plan/parser-migration.js.map +1 -1
  227. package/dist/server/services/plan/parser.d.ts.map +1 -1
  228. package/dist/server/services/plan/parser.js +0 -1
  229. package/dist/server/services/plan/parser.js.map +1 -1
  230. package/dist/server/services/plan/progress-log.d.ts +11 -0
  231. package/dist/server/services/plan/progress-log.d.ts.map +1 -0
  232. package/dist/server/services/plan/progress-log.js +80 -0
  233. package/dist/server/services/plan/progress-log.js.map +1 -0
  234. package/dist/server/services/plan/prompt-builder.d.ts.map +1 -1
  235. package/dist/server/services/plan/prompt-builder.js +48 -32
  236. package/dist/server/services/plan/prompt-builder.js.map +1 -1
  237. package/dist/server/services/plan/readiness-planner.d.ts +15 -0
  238. package/dist/server/services/plan/readiness-planner.d.ts.map +1 -0
  239. package/dist/server/services/plan/readiness-planner.js +40 -0
  240. package/dist/server/services/plan/readiness-planner.js.map +1 -0
  241. package/dist/server/services/plan/review-gate.d.ts +31 -0
  242. package/dist/server/services/plan/review-gate.d.ts.map +1 -1
  243. package/dist/server/services/plan/review-gate.js +52 -3
  244. package/dist/server/services/plan/review-gate.js.map +1 -1
  245. package/dist/server/services/plan/state-reconciler.d.ts.map +1 -1
  246. package/dist/server/services/plan/state-reconciler.js +0 -1
  247. package/dist/server/services/plan/state-reconciler.js.map +1 -1
  248. package/dist/server/services/plan/types.d.ts.map +1 -1
  249. package/dist/server/services/plan/types.js +0 -1
  250. package/dist/server/services/plan/types.js.map +1 -1
  251. package/dist/server/services/plan/watcher.d.ts.map +1 -1
  252. package/dist/server/services/plan/watcher.js +0 -1
  253. package/dist/server/services/plan/watcher.js.map +1 -1
  254. package/dist/server/services/platform-credentials.d.ts.map +1 -1
  255. package/dist/server/services/platform-credentials.js +0 -1
  256. package/dist/server/services/platform-credentials.js.map +1 -1
  257. package/dist/server/services/platform-token-lifecycle.d.ts +70 -0
  258. package/dist/server/services/platform-token-lifecycle.d.ts.map +1 -0
  259. package/dist/server/services/platform-token-lifecycle.js +156 -0
  260. package/dist/server/services/platform-token-lifecycle.js.map +1 -0
  261. package/dist/server/services/platform.d.ts +25 -4
  262. package/dist/server/services/platform.d.ts.map +1 -1
  263. package/dist/server/services/platform.js +150 -92
  264. package/dist/server/services/platform.js.map +1 -1
  265. package/dist/server/services/sentry.d.ts.map +1 -1
  266. package/dist/server/services/sentry.js +0 -1
  267. package/dist/server/services/sentry.js.map +1 -1
  268. package/dist/server/services/settings.d.ts.map +1 -1
  269. package/dist/server/services/settings.js +0 -1
  270. package/dist/server/services/settings.js.map +1 -1
  271. package/dist/server/services/terminal/pty-manager.d.ts.map +1 -1
  272. package/dist/server/services/terminal/pty-manager.js +0 -1
  273. package/dist/server/services/terminal/pty-manager.js.map +1 -1
  274. package/dist/server/services/terminal/pty-utils.d.ts.map +1 -1
  275. package/dist/server/services/terminal/pty-utils.js +0 -1
  276. package/dist/server/services/terminal/pty-utils.js.map +1 -1
  277. package/dist/server/services/websocket/autocomplete.d.ts.map +1 -1
  278. package/dist/server/services/websocket/autocomplete.js +0 -1
  279. package/dist/server/services/websocket/autocomplete.js.map +1 -1
  280. package/dist/server/services/websocket/file-definition-handlers.d.ts.map +1 -1
  281. package/dist/server/services/websocket/file-definition-handlers.js +0 -1
  282. package/dist/server/services/websocket/file-definition-handlers.js.map +1 -1
  283. package/dist/server/services/websocket/file-download-handler.d.ts +17 -0
  284. package/dist/server/services/websocket/file-download-handler.d.ts.map +1 -0
  285. package/dist/server/services/websocket/file-download-handler.js +164 -0
  286. package/dist/server/services/websocket/file-download-handler.js.map +1 -0
  287. package/dist/server/services/websocket/file-explorer-handlers.d.ts.map +1 -1
  288. package/dist/server/services/websocket/file-explorer-handlers.js +0 -1
  289. package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -1
  290. package/dist/server/services/websocket/file-search-handlers.d.ts.map +1 -1
  291. package/dist/server/services/websocket/file-search-handlers.js +0 -1
  292. package/dist/server/services/websocket/file-search-handlers.js.map +1 -1
  293. package/dist/server/services/websocket/file-upload-handler.d.ts +2 -3
  294. package/dist/server/services/websocket/file-upload-handler.d.ts.map +1 -1
  295. package/dist/server/services/websocket/file-upload-handler.js +4 -7
  296. package/dist/server/services/websocket/file-upload-handler.js.map +1 -1
  297. package/dist/server/services/websocket/file-utils.d.ts.map +1 -1
  298. package/dist/server/services/websocket/file-utils.js +0 -1
  299. package/dist/server/services/websocket/file-utils.js.map +1 -1
  300. package/dist/server/services/websocket/git-branch-handlers.d.ts.map +1 -1
  301. package/dist/server/services/websocket/git-branch-handlers.js +0 -1
  302. package/dist/server/services/websocket/git-branch-handlers.js.map +1 -1
  303. package/dist/server/services/websocket/git-diff-handlers.d.ts.map +1 -1
  304. package/dist/server/services/websocket/git-diff-handlers.js +0 -1
  305. package/dist/server/services/websocket/git-diff-handlers.js.map +1 -1
  306. package/dist/server/services/websocket/git-handlers.d.ts.map +1 -1
  307. package/dist/server/services/websocket/git-handlers.js +58 -6
  308. package/dist/server/services/websocket/git-handlers.js.map +1 -1
  309. package/dist/server/services/websocket/git-head-watcher.d.ts.map +1 -1
  310. package/dist/server/services/websocket/git-head-watcher.js +0 -1
  311. package/dist/server/services/websocket/git-head-watcher.js.map +1 -1
  312. package/dist/server/services/websocket/git-log-handlers.d.ts.map +1 -1
  313. package/dist/server/services/websocket/git-log-handlers.js +0 -1
  314. package/dist/server/services/websocket/git-log-handlers.js.map +1 -1
  315. package/dist/server/services/websocket/git-pr-handlers.d.ts.map +1 -1
  316. package/dist/server/services/websocket/git-pr-handlers.js +0 -1
  317. package/dist/server/services/websocket/git-pr-handlers.js.map +1 -1
  318. package/dist/server/services/websocket/git-tag-handlers.d.ts.map +1 -1
  319. package/dist/server/services/websocket/git-tag-handlers.js +0 -1
  320. package/dist/server/services/websocket/git-tag-handlers.js.map +1 -1
  321. package/dist/server/services/websocket/git-utils.d.ts +18 -3
  322. package/dist/server/services/websocket/git-utils.d.ts.map +1 -1
  323. package/dist/server/services/websocket/git-utils.js +58 -8
  324. package/dist/server/services/websocket/git-utils.js.map +1 -1
  325. package/dist/server/services/websocket/git-worktree-handlers.d.ts.map +1 -1
  326. package/dist/server/services/websocket/git-worktree-handlers.js +258 -16
  327. package/dist/server/services/websocket/git-worktree-handlers.js.map +1 -1
  328. package/dist/server/services/websocket/handler-context.d.ts +15 -0
  329. package/dist/server/services/websocket/handler-context.d.ts.map +1 -1
  330. package/dist/server/services/websocket/handler-context.js +0 -1
  331. package/dist/server/services/websocket/handler-context.js.map +1 -1
  332. package/dist/server/services/websocket/handler.d.ts +7 -0
  333. package/dist/server/services/websocket/handler.d.ts.map +1 -1
  334. package/dist/server/services/websocket/handler.js +76 -15
  335. package/dist/server/services/websocket/handler.js.map +1 -1
  336. package/dist/server/services/websocket/index.d.ts.map +1 -1
  337. package/dist/server/services/websocket/index.js +0 -1
  338. package/dist/server/services/websocket/index.js.map +1 -1
  339. package/dist/server/services/websocket/msg-id-tracker.d.ts +21 -0
  340. package/dist/server/services/websocket/msg-id-tracker.d.ts.map +1 -0
  341. package/dist/server/services/websocket/msg-id-tracker.js +76 -0
  342. package/dist/server/services/websocket/msg-id-tracker.js.map +1 -0
  343. package/dist/server/services/websocket/plan-board-handlers.d.ts.map +1 -1
  344. package/dist/server/services/websocket/plan-board-handlers.js +0 -1
  345. package/dist/server/services/websocket/plan-board-handlers.js.map +1 -1
  346. package/dist/server/services/websocket/plan-execution-handlers.d.ts.map +1 -1
  347. package/dist/server/services/websocket/plan-execution-handlers.js +6 -2
  348. package/dist/server/services/websocket/plan-execution-handlers.js.map +1 -1
  349. package/dist/server/services/websocket/plan-handlers.d.ts.map +1 -1
  350. package/dist/server/services/websocket/plan-handlers.js +0 -1
  351. package/dist/server/services/websocket/plan-handlers.js.map +1 -1
  352. package/dist/server/services/websocket/plan-helpers.d.ts.map +1 -1
  353. package/dist/server/services/websocket/plan-helpers.js +0 -1
  354. package/dist/server/services/websocket/plan-helpers.js.map +1 -1
  355. package/dist/server/services/websocket/plan-issue-handlers.d.ts.map +1 -1
  356. package/dist/server/services/websocket/plan-issue-handlers.js +0 -1
  357. package/dist/server/services/websocket/plan-issue-handlers.js.map +1 -1
  358. package/dist/server/services/websocket/plan-sprint-handlers.d.ts.map +1 -1
  359. package/dist/server/services/websocket/plan-sprint-handlers.js +0 -1
  360. package/dist/server/services/websocket/plan-sprint-handlers.js.map +1 -1
  361. package/dist/server/services/websocket/quality-complexity.d.ts.map +1 -1
  362. package/dist/server/services/websocket/quality-complexity.js +0 -1
  363. package/dist/server/services/websocket/quality-complexity.js.map +1 -1
  364. package/dist/server/services/websocket/quality-grading.d.ts +46 -0
  365. package/dist/server/services/websocket/quality-grading.d.ts.map +1 -0
  366. package/dist/server/services/websocket/quality-grading.js +482 -0
  367. package/dist/server/services/websocket/quality-grading.js.map +1 -0
  368. package/dist/server/services/websocket/quality-handlers.d.ts.map +1 -1
  369. package/dist/server/services/websocket/quality-handlers.js +15 -4
  370. package/dist/server/services/websocket/quality-handlers.js.map +1 -1
  371. package/dist/server/services/websocket/quality-linting.d.ts.map +1 -1
  372. package/dist/server/services/websocket/quality-linting.js +0 -1
  373. package/dist/server/services/websocket/quality-linting.js.map +1 -1
  374. package/dist/server/services/websocket/quality-persistence.d.ts +14 -0
  375. package/dist/server/services/websocket/quality-persistence.d.ts.map +1 -1
  376. package/dist/server/services/websocket/quality-persistence.js +28 -12
  377. package/dist/server/services/websocket/quality-persistence.js.map +1 -1
  378. package/dist/server/services/websocket/quality-review-agent.d.ts.map +1 -1
  379. package/dist/server/services/websocket/quality-review-agent.js +2 -3
  380. package/dist/server/services/websocket/quality-review-agent.js.map +1 -1
  381. package/dist/server/services/websocket/quality-service.d.ts +3 -1
  382. package/dist/server/services/websocket/quality-service.d.ts.map +1 -1
  383. package/dist/server/services/websocket/quality-service.js +53 -58
  384. package/dist/server/services/websocket/quality-service.js.map +1 -1
  385. package/dist/server/services/websocket/quality-tools.d.ts +1 -1
  386. package/dist/server/services/websocket/quality-tools.d.ts.map +1 -1
  387. package/dist/server/services/websocket/quality-tools.js +6 -3
  388. package/dist/server/services/websocket/quality-tools.js.map +1 -1
  389. package/dist/server/services/websocket/quality-types.d.ts +18 -2
  390. package/dist/server/services/websocket/quality-types.d.ts.map +1 -1
  391. package/dist/server/services/websocket/quality-types.js +0 -1
  392. package/dist/server/services/websocket/quality-types.js.map +1 -1
  393. package/dist/server/services/websocket/session-handlers.d.ts +48 -2
  394. package/dist/server/services/websocket/session-handlers.d.ts.map +1 -1
  395. package/dist/server/services/websocket/session-handlers.js +204 -66
  396. package/dist/server/services/websocket/session-handlers.js.map +1 -1
  397. package/dist/server/services/websocket/session-history.d.ts.map +1 -1
  398. package/dist/server/services/websocket/session-history.js +0 -1
  399. package/dist/server/services/websocket/session-history.js.map +1 -1
  400. package/dist/server/services/websocket/session-initialization.d.ts +2 -2
  401. package/dist/server/services/websocket/session-initialization.d.ts.map +1 -1
  402. package/dist/server/services/websocket/session-initialization.js +75 -18
  403. package/dist/server/services/websocket/session-initialization.js.map +1 -1
  404. package/dist/server/services/websocket/session-registry.d.ts +29 -1
  405. package/dist/server/services/websocket/session-registry.d.ts.map +1 -1
  406. package/dist/server/services/websocket/session-registry.js +53 -5
  407. package/dist/server/services/websocket/session-registry.js.map +1 -1
  408. package/dist/server/services/websocket/settings-handlers.d.ts.map +1 -1
  409. package/dist/server/services/websocket/settings-handlers.js +0 -1
  410. package/dist/server/services/websocket/settings-handlers.js.map +1 -1
  411. package/dist/server/services/websocket/skill-handlers.d.ts.map +1 -1
  412. package/dist/server/services/websocket/skill-handlers.js +0 -1
  413. package/dist/server/services/websocket/skill-handlers.js.map +1 -1
  414. package/dist/server/services/websocket/skill-watcher.d.ts.map +1 -1
  415. package/dist/server/services/websocket/skill-watcher.js +0 -1
  416. package/dist/server/services/websocket/skill-watcher.js.map +1 -1
  417. package/dist/server/services/websocket/tab-broadcast.d.ts +24 -0
  418. package/dist/server/services/websocket/tab-broadcast.d.ts.map +1 -0
  419. package/dist/server/services/websocket/tab-broadcast.js +12 -0
  420. package/dist/server/services/websocket/tab-broadcast.js.map +1 -0
  421. package/dist/server/services/websocket/tab-event-buffer.d.ts +103 -0
  422. package/dist/server/services/websocket/tab-event-buffer.d.ts.map +1 -0
  423. package/dist/server/services/websocket/tab-event-buffer.js +106 -0
  424. package/dist/server/services/websocket/tab-event-buffer.js.map +1 -0
  425. package/dist/server/services/websocket/tab-event-replay.d.ts +20 -0
  426. package/dist/server/services/websocket/tab-event-replay.d.ts.map +1 -0
  427. package/dist/server/services/websocket/tab-event-replay.js +20 -0
  428. package/dist/server/services/websocket/tab-event-replay.js.map +1 -0
  429. package/dist/server/services/websocket/tab-handlers.d.ts +0 -1
  430. package/dist/server/services/websocket/tab-handlers.d.ts.map +1 -1
  431. package/dist/server/services/websocket/tab-handlers.js +2 -10
  432. package/dist/server/services/websocket/tab-handlers.js.map +1 -1
  433. package/dist/server/services/websocket/terminal-handlers.d.ts.map +1 -1
  434. package/dist/server/services/websocket/terminal-handlers.js +39 -4
  435. package/dist/server/services/websocket/terminal-handlers.js.map +1 -1
  436. package/dist/server/services/websocket/types.d.ts +17 -8
  437. package/dist/server/services/websocket/types.d.ts.map +1 -1
  438. package/dist/server/services/websocket/types.js +8 -7
  439. package/dist/server/services/websocket/types.js.map +1 -1
  440. package/dist/server/utils/agent-manager.d.ts.map +1 -1
  441. package/dist/server/utils/agent-manager.js +0 -1
  442. package/dist/server/utils/agent-manager.js.map +1 -1
  443. package/dist/server/utils/paths.d.ts.map +1 -1
  444. package/dist/server/utils/paths.js +0 -1
  445. package/dist/server/utils/paths.js.map +1 -1
  446. package/dist/server/utils/port-manager.d.ts.map +1 -1
  447. package/dist/server/utils/port-manager.js +0 -1
  448. package/dist/server/utils/port-manager.js.map +1 -1
  449. package/dist/server/utils/port.d.ts.map +1 -1
  450. package/dist/server/utils/port.js +0 -1
  451. package/dist/server/utils/port.js.map +1 -1
  452. package/package.json +2 -2
  453. package/server/README.md +1 -1
  454. package/server/cli/headless/claude-invoker-process.ts +0 -1
  455. package/server/cli/headless/claude-invoker-stall.ts +7 -3
  456. package/server/cli/headless/claude-invoker-stream.ts +0 -1
  457. package/server/cli/headless/claude-invoker-tools.ts +0 -1
  458. package/server/cli/headless/claude-invoker.ts +1 -2
  459. package/server/cli/headless/haiku-assessments.ts +0 -1
  460. package/server/cli/headless/headless-logger.ts +0 -1
  461. package/server/cli/headless/index.ts +0 -1
  462. package/server/cli/headless/native-timeout-detector.ts +0 -1
  463. package/server/cli/headless/output-utils.ts +0 -1
  464. package/server/cli/headless/prompt-utils.ts +0 -1
  465. package/server/cli/headless/resilient-runner.ts +0 -1
  466. package/server/cli/headless/retry-strategies.ts +0 -1
  467. package/server/cli/headless/runner.ts +67 -73
  468. package/server/cli/headless/stall-assessor.ts +9 -5
  469. package/server/cli/headless/tool-watchdog.ts +0 -1
  470. package/server/cli/headless/types.ts +1 -2
  471. package/server/cli/improvisation-attachments.ts +0 -1
  472. package/server/cli/improvisation-history-store.ts +61 -0
  473. package/server/cli/improvisation-movements.ts +119 -0
  474. package/server/cli/improvisation-output-queue.ts +41 -0
  475. package/server/cli/improvisation-retry.ts +25 -601
  476. package/server/cli/improvisation-session-manager.ts +74 -161
  477. package/server/cli/improvisation-types.ts +0 -1
  478. package/server/cli/retry/retry-best-result.ts +69 -0
  479. package/server/cli/retry/retry-context-loss.ts +86 -0
  480. package/server/cli/retry/retry-premature-completion.ts +112 -0
  481. package/server/cli/retry/retry-recovery-strategies.ts +246 -0
  482. package/server/cli/retry/retry-resume-strategy.ts +32 -0
  483. package/server/cli/retry/retry-runner-factory.ts +69 -0
  484. package/server/cli/retry/retry-tool-results.ts +30 -0
  485. package/server/cli/retry/retry-types.ts +31 -0
  486. package/server/index.ts +37 -124
  487. package/server/mcp/bouncer-cli.ts +0 -1
  488. package/server/mcp/bouncer-haiku.ts +0 -1
  489. package/server/mcp/bouncer-integration.ts +0 -1
  490. package/server/mcp/security-analysis.ts +0 -1
  491. package/server/mcp/security-audit.ts +0 -1
  492. package/server/mcp/security-patterns.ts +0 -1
  493. package/server/mcp/server.ts +0 -1
  494. package/server/routes/files.ts +0 -1
  495. package/server/routes/improvise.ts +0 -1
  496. package/server/routes/index.ts +0 -1
  497. package/server/routes/instances.ts +0 -1
  498. package/server/routes/notifications.ts +0 -1
  499. package/server/server-setup.ts +126 -2
  500. package/server/services/analytics.ts +0 -1
  501. package/server/services/auth.ts +0 -1
  502. package/server/services/client-id.ts +0 -1
  503. package/server/services/file-explorer-ops.ts +0 -1
  504. package/server/services/files.ts +0 -1
  505. package/server/services/instances.ts +0 -1
  506. package/server/services/pathUtils.ts +0 -1
  507. package/server/services/plan/agent-loader.ts +0 -1
  508. package/server/services/plan/agents/assess-stall.md +11 -4
  509. package/server/services/plan/agents/code-review.md +13 -11
  510. package/server/services/plan/board-config.ts +121 -0
  511. package/server/services/plan/composer.ts +7 -6
  512. package/server/services/plan/config-installer.ts +0 -1
  513. package/server/services/plan/dependency-resolver.ts +0 -1
  514. package/server/services/plan/executor.ts +259 -470
  515. package/server/services/plan/front-matter.ts +0 -1
  516. package/server/services/plan/issue-classification.ts +0 -1
  517. package/server/services/plan/issue-loader.ts +63 -0
  518. package/server/services/plan/issue-prompt-builder.ts +0 -1
  519. package/server/services/plan/issue-retry.ts +5 -2
  520. package/server/services/plan/issue-writer.ts +136 -0
  521. package/server/services/plan/output-manager.ts +2 -2
  522. package/server/services/plan/parser-core.ts +0 -1
  523. package/server/services/plan/parser-migration.ts +0 -1
  524. package/server/services/plan/parser.ts +0 -1
  525. package/server/services/plan/progress-log.ts +91 -0
  526. package/server/services/plan/prompt-builder.ts +73 -36
  527. package/server/services/plan/readiness-planner.ts +49 -0
  528. package/server/services/plan/review-gate.ts +102 -3
  529. package/server/services/plan/state-reconciler.ts +0 -1
  530. package/server/services/plan/types.ts +0 -1
  531. package/server/services/plan/watcher.ts +0 -1
  532. package/server/services/platform-credentials.ts +0 -1
  533. package/server/services/platform-token-lifecycle.ts +171 -0
  534. package/server/services/platform.ts +168 -105
  535. package/server/services/sentry.ts +0 -1
  536. package/server/services/settings.ts +0 -1
  537. package/server/services/terminal/pty-manager.ts +0 -1
  538. package/server/services/terminal/pty-utils.ts +0 -1
  539. package/server/services/websocket/autocomplete.ts +0 -1
  540. package/server/services/websocket/file-definition-handlers.ts +0 -1
  541. package/server/services/websocket/file-download-handler.ts +190 -0
  542. package/server/services/websocket/file-explorer-handlers.ts +0 -1
  543. package/server/services/websocket/file-search-handlers.ts +0 -1
  544. package/server/services/websocket/file-upload-handler.ts +6 -5
  545. package/server/services/websocket/file-utils.ts +0 -1
  546. package/server/services/websocket/git-branch-handlers.ts +0 -1
  547. package/server/services/websocket/git-diff-handlers.ts +0 -1
  548. package/server/services/websocket/git-handlers.ts +66 -10
  549. package/server/services/websocket/git-head-watcher.ts +0 -1
  550. package/server/services/websocket/git-log-handlers.ts +0 -1
  551. package/server/services/websocket/git-pr-handlers.ts +0 -1
  552. package/server/services/websocket/git-tag-handlers.ts +0 -1
  553. package/server/services/websocket/git-utils.ts +69 -9
  554. package/server/services/websocket/git-worktree-handlers.ts +289 -19
  555. package/server/services/websocket/handler-context.ts +15 -1
  556. package/server/services/websocket/handler.ts +79 -16
  557. package/server/services/websocket/index.ts +0 -1
  558. package/server/services/websocket/msg-id-tracker.ts +83 -0
  559. package/server/services/websocket/plan-board-handlers.ts +0 -1
  560. package/server/services/websocket/plan-execution-handlers.ts +6 -2
  561. package/server/services/websocket/plan-handlers.ts +0 -1
  562. package/server/services/websocket/plan-helpers.ts +0 -1
  563. package/server/services/websocket/plan-issue-handlers.ts +0 -1
  564. package/server/services/websocket/plan-sprint-handlers.ts +0 -1
  565. package/server/services/websocket/quality-complexity.ts +0 -1
  566. package/server/services/websocket/quality-grading.ts +611 -0
  567. package/server/services/websocket/quality-handlers.ts +16 -4
  568. package/server/services/websocket/quality-linting.ts +0 -1
  569. package/server/services/websocket/quality-persistence.ts +30 -8
  570. package/server/services/websocket/quality-review-agent.ts +2 -3
  571. package/server/services/websocket/quality-service.ts +54 -55
  572. package/server/services/websocket/quality-tools.ts +11 -3
  573. package/server/services/websocket/quality-types.ts +21 -3
  574. package/server/services/websocket/session-handlers.ts +213 -69
  575. package/server/services/websocket/session-history.ts +0 -1
  576. package/server/services/websocket/session-initialization.ts +83 -20
  577. package/server/services/websocket/session-registry.ts +61 -5
  578. package/server/services/websocket/settings-handlers.ts +0 -1
  579. package/server/services/websocket/skill-handlers.ts +0 -1
  580. package/server/services/websocket/skill-watcher.ts +0 -1
  581. package/server/services/websocket/tab-broadcast.ts +37 -0
  582. package/server/services/websocket/tab-event-buffer.ts +158 -0
  583. package/server/services/websocket/tab-event-replay.ts +41 -0
  584. package/server/services/websocket/tab-handlers.ts +2 -10
  585. package/server/services/websocket/terminal-handlers.ts +39 -3
  586. package/server/services/websocket/types.ts +19 -7
  587. package/server/utils/agent-manager.ts +0 -1
  588. package/server/utils/paths.ts +0 -1
  589. package/server/utils/port-manager.ts +0 -1
  590. package/server/utils/port.ts +0 -1
@@ -0,0 +1,611 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+
3
+ // ============================================================================
4
+ // Multi-Dimensional Quality Grading
5
+ // ============================================================================
6
+ //
7
+ // Pure logic for the three-dimension grading model:
8
+ // - Security — severity-threshold (worst severity issue determines grade)
9
+ // - Reliability — severity-threshold, slightly more lenient than Security
10
+ // - Maintainability — density-based (issues / KLOC) with a severity escape hatch
11
+ //
12
+ // Rationale (why these specific bands):
13
+ // The previous single-score exponential-decay model conflated security holes
14
+ // with prettier complaints. Industry tools (SonarQube, Code Climate, CodeScene)
15
+ // all separate severity-driven dimensions from aggregate metrics so that a
16
+ // critical issue can never be "averaged away" by a clean lint score.
17
+ //
18
+ // All functions in this module are pure: same inputs -> same outputs, no I/O.
19
+ // ============================================================================
20
+
21
+ // ============================================================================
22
+ // Types
23
+ // ============================================================================
24
+
25
+ export type DimensionName = 'security' | 'reliability' | 'maintainability';
26
+ export type Grade = 'A' | 'B' | 'C' | 'D' | 'F' | 'N/A';
27
+ type Severity = 'critical' | 'high' | 'medium' | 'low';
28
+
29
+ export interface DimensionScore {
30
+ name: DimensionName;
31
+ score: number;
32
+ grade: Grade;
33
+ rationale: string;
34
+ available: boolean;
35
+ findingCount: number;
36
+ worstSeverity: Severity | null;
37
+ }
38
+
39
+ export interface QualityGate {
40
+ passed: boolean;
41
+ failingConditions: string[];
42
+ }
43
+
44
+ export interface QualityRating {
45
+ overall: { score: number; grade: Grade };
46
+ dimensions: DimensionScore[];
47
+ qualityGate: QualityGate;
48
+ gradeRationale: string;
49
+ }
50
+
51
+ // ============================================================================
52
+ // Category -> Dimension Mapping
53
+ // ============================================================================
54
+
55
+ const SECURITY_CATEGORIES = new Set<string>(['security']);
56
+ const RELIABILITY_CATEGORIES = new Set<string>(['bugs', 'logic', 'performance', 'complexity']);
57
+ const MAINTAINABILITY_CATEGORIES = new Set<string>([
58
+ 'lint',
59
+ 'linting',
60
+ 'format',
61
+ 'file-length',
62
+ 'function-length',
63
+ 'architecture',
64
+ 'oop',
65
+ 'maintainability',
66
+ ]);
67
+
68
+ /**
69
+ * Map a finding category to one of the three quality dimensions.
70
+ * Unknown categories default to maintainability (the catch-all bucket) so
71
+ * that surprise categories never silently disappear from the grade.
72
+ */
73
+ export function categoryToDimension(category: string): DimensionName {
74
+ if (SECURITY_CATEGORIES.has(category)) return 'security';
75
+ if (RELIABILITY_CATEGORIES.has(category)) return 'reliability';
76
+ if (MAINTAINABILITY_CATEGORIES.has(category)) return 'maintainability';
77
+ return 'maintainability';
78
+ }
79
+
80
+ // ============================================================================
81
+ // Legacy Fallback
82
+ // ============================================================================
83
+
84
+ /**
85
+ * Score-to-grade conversion used by legacy callers that still operate on a
86
+ * single 0-100 number. The new multi-dimensional path computes grades
87
+ * directly from finding shape; this remains for backward compatibility.
88
+ */
89
+ export function gradeFromScore(score: number): Grade {
90
+ if (score >= 90) return 'A';
91
+ if (score >= 80) return 'B';
92
+ if (score >= 70) return 'C';
93
+ if (score >= 60) return 'D';
94
+ return 'F';
95
+ }
96
+
97
+ // ============================================================================
98
+ // Score Bands
99
+ // ============================================================================
100
+
101
+ const BAND_TOP: Record<Exclude<Grade, 'N/A'>, number> = {
102
+ A: 100,
103
+ B: 89,
104
+ C: 79,
105
+ D: 69,
106
+ F: 59,
107
+ };
108
+
109
+ const BAND_BOTTOM: Record<Exclude<Grade, 'N/A'>, number> = {
110
+ A: 90,
111
+ B: 80,
112
+ C: 70,
113
+ D: 60,
114
+ F: 0,
115
+ };
116
+
117
+ /**
118
+ * Linearly interpolate a score within a grade's band.
119
+ *
120
+ * `position` is in [0, 1]: 0 means "as bad as this grade gets" (band bottom),
121
+ * 1 means "as good as this grade gets" (band top, just below the next grade).
122
+ */
123
+ function scoreInBand(grade: Exclude<Grade, 'N/A'>, position: number): number {
124
+ const clamped = Math.max(0, Math.min(1, position));
125
+ const bottom = BAND_BOTTOM[grade];
126
+ const top = BAND_TOP[grade];
127
+ return Math.round(bottom + (top - bottom) * clamped);
128
+ }
129
+
130
+ // ============================================================================
131
+ // Severity Helpers
132
+ // ============================================================================
133
+
134
+ function isSeverity(s: string): s is Severity {
135
+ return s === 'critical' || s === 'high' || s === 'medium' || s === 'low';
136
+ }
137
+
138
+ interface SeverityCounts {
139
+ critical: number;
140
+ high: number;
141
+ medium: number;
142
+ low: number;
143
+ total: number;
144
+ }
145
+
146
+ function countSeverities(findings: Array<{ severity: string }>): SeverityCounts {
147
+ const counts: SeverityCounts = { critical: 0, high: 0, medium: 0, low: 0, total: 0 };
148
+ for (const f of findings) {
149
+ if (!isSeverity(f.severity)) continue;
150
+ counts[f.severity]++;
151
+ counts.total++;
152
+ }
153
+ return counts;
154
+ }
155
+
156
+ function worstSeverity(counts: SeverityCounts): Severity | null {
157
+ if (counts.critical > 0) return 'critical';
158
+ if (counts.high > 0) return 'high';
159
+ if (counts.medium > 0) return 'medium';
160
+ if (counts.low > 0) return 'low';
161
+ return null;
162
+ }
163
+
164
+ // ============================================================================
165
+ // Security Dimension
166
+ // ============================================================================
167
+
168
+ /**
169
+ * Security grading — strictest of the three dimensions. Any medium-or-worse
170
+ * security finding immediately drops the grade below B because security
171
+ * issues can't be amortized over codebase size.
172
+ *
173
+ * Within-band score: more findings at the threshold severity -> lower score.
174
+ * The interpolation favors "fewer issues is meaningfully better" so 1 medium
175
+ * scores higher than 5 mediums even though both are grade C.
176
+ */
177
+ function gradeSecurity(findings: Array<{ severity: string }>): DimensionScore {
178
+ const counts = countSeverities(findings);
179
+ const worst = worstSeverity(counts);
180
+
181
+ if (counts.total === 0) {
182
+ return {
183
+ name: 'security',
184
+ score: 100,
185
+ grade: 'A',
186
+ rationale: '0 security findings',
187
+ available: true,
188
+ findingCount: 0,
189
+ worstSeverity: null,
190
+ };
191
+ }
192
+
193
+ let grade: Exclude<Grade, 'N/A'>;
194
+ let position: number;
195
+ let rationale: string;
196
+
197
+ if (counts.critical > 0) {
198
+ grade = 'F';
199
+ // F band: fewer criticals -> higher within-band, but still F.
200
+ position = 1 / (1 + counts.critical);
201
+ rationale = `${counts.critical} critical-severity security ${pluralize('issue', counts.critical)}`;
202
+ } else if (counts.high > 0) {
203
+ grade = 'D';
204
+ position = 1 / (1 + counts.high);
205
+ rationale = `${counts.high} high-severity security ${pluralize('issue', counts.high)}`;
206
+ } else if (counts.medium > 0) {
207
+ grade = 'C';
208
+ position = 1 / (1 + counts.medium);
209
+ rationale = `${counts.medium} medium-severity security ${pluralize('issue', counts.medium)}`;
210
+ } else {
211
+ // Only low-severity findings.
212
+ grade = 'B';
213
+ // 1 low -> top of B (89); more lows -> down toward 80.
214
+ position = 1 / Math.max(1, counts.low);
215
+ rationale = `${counts.low} low-severity security ${pluralize('issue', counts.low)}`;
216
+ }
217
+
218
+ return {
219
+ name: 'security',
220
+ score: scoreInBand(grade, position),
221
+ grade,
222
+ rationale,
223
+ available: true,
224
+ findingCount: counts.total,
225
+ worstSeverity: worst,
226
+ };
227
+ }
228
+
229
+ // ============================================================================
230
+ // Reliability Dimension
231
+ // ============================================================================
232
+
233
+ interface BandResult {
234
+ grade: Exclude<Grade, 'N/A'>;
235
+ position: number;
236
+ rationale: string;
237
+ }
238
+
239
+ function reliabilityBandClean(counts: SeverityCounts): BandResult {
240
+ const position = counts.total === 0 ? 1 : 0.5;
241
+ const rationale = counts.total === 0 ? '0 reliability findings' : '1 low-severity reliability issue';
242
+ return { grade: 'A', position, rationale };
243
+ }
244
+
245
+ function reliabilityBandSevere(counts: SeverityCounts): BandResult | null {
246
+ if (counts.critical > 0) {
247
+ return {
248
+ grade: 'F',
249
+ position: 1 / (1 + counts.critical),
250
+ rationale: `${counts.critical} critical-severity ${pluralize('bug', counts.critical)}`,
251
+ };
252
+ }
253
+ if (counts.high >= 2) {
254
+ return {
255
+ grade: 'D',
256
+ position: 1 / (1 + (counts.high - 1)),
257
+ rationale: `${counts.high} high-severity ${pluralize('bug', counts.high)}`,
258
+ };
259
+ }
260
+ return null;
261
+ }
262
+
263
+ function reliabilityBandMid(counts: SeverityCounts): BandResult {
264
+ if (counts.high >= 1) {
265
+ return {
266
+ grade: 'C',
267
+ position: 1 / (1 + counts.high),
268
+ rationale: `${counts.high} high-severity ${pluralize('bug', counts.high)}`,
269
+ };
270
+ }
271
+ if (counts.medium >= 3) {
272
+ return {
273
+ grade: 'C',
274
+ position: 1 / Math.max(1, counts.medium - 2),
275
+ rationale: `${counts.medium} medium-severity reliability ${pluralize('issue', counts.medium)}`,
276
+ };
277
+ }
278
+ if (counts.medium >= 1) {
279
+ return {
280
+ grade: 'B',
281
+ position: 1 / Math.max(1, counts.medium),
282
+ rationale: `${counts.medium} medium-severity reliability ${pluralize('issue', counts.medium)}`,
283
+ };
284
+ }
285
+ // Only low-severity findings, > 1 of them.
286
+ return {
287
+ grade: 'B',
288
+ position: 1 / Math.max(1, counts.low - 1),
289
+ rationale: `${counts.low} low-severity reliability ${pluralize('issue', counts.low)}`,
290
+ };
291
+ }
292
+
293
+ /**
294
+ * Reliability grading — slightly more lenient than Security because not every
295
+ * complexity warning is a runtime defect. A single low-severity logic issue
296
+ * still earns an A; medium issues escalate gradually.
297
+ */
298
+ function gradeReliability(findings: Array<{ severity: string }>): DimensionScore {
299
+ const counts = countSeverities(findings);
300
+ const worst = worstSeverity(counts);
301
+ const isClean = counts.total === 0 || (counts.low <= 1 && counts.medium === 0 && counts.high === 0 && counts.critical === 0);
302
+ const band = isClean
303
+ ? reliabilityBandClean(counts)
304
+ : reliabilityBandSevere(counts) ?? reliabilityBandMid(counts);
305
+
306
+ return {
307
+ name: 'reliability',
308
+ score: scoreInBand(band.grade, band.position),
309
+ grade: band.grade,
310
+ rationale: band.rationale,
311
+ available: true,
312
+ findingCount: counts.total,
313
+ worstSeverity: worst,
314
+ };
315
+ }
316
+
317
+ // ============================================================================
318
+ // Maintainability Dimension
319
+ // ============================================================================
320
+
321
+ interface MaintainabilityBand {
322
+ grade: Exclude<Grade, 'N/A'>;
323
+ position: number;
324
+ label: string;
325
+ }
326
+
327
+ function maintainabilityByCount(n: number): MaintainabilityBand {
328
+ const label = `${n} maintainability ${pluralize('issue', n)}`;
329
+ if (n <= 5) return { grade: 'A', position: 1 - n / 5, label };
330
+ if (n <= 15) return { grade: 'B', position: 1 - (n - 5) / 10, label };
331
+ if (n <= 30) return { grade: 'C', position: 1 - (n - 15) / 15, label };
332
+ if (n <= 60) return { grade: 'D', position: 1 - (n - 30) / 30, label };
333
+ return { grade: 'F', position: 1 / (1 + (n - 60) / 30), label };
334
+ }
335
+
336
+ function maintainabilityByDensity(n: number, kloc: number): MaintainabilityBand {
337
+ const density = n / kloc;
338
+ const label = `${roundOne(density)} ${pluralize('issue', n)} / KLOC`;
339
+ if (density < 5) return { grade: 'A', position: 1 - density / 5, label };
340
+ if (density < 10) return { grade: 'B', position: 1 - (density - 5) / 5, label };
341
+ if (density < 25) return { grade: 'C', position: 1 - (density - 10) / 15, label };
342
+ if (density < 50) return { grade: 'D', position: 1 - (density - 25) / 25, label };
343
+ return { grade: 'F', position: 1 / (1 + (density - 50) / 25), label };
344
+ }
345
+
346
+ interface SeverityEscape {
347
+ grade: Exclude<Grade, 'N/A'>;
348
+ note: string;
349
+ }
350
+
351
+ function maintainabilityEscape(counts: SeverityCounts): SeverityEscape | null {
352
+ if (counts.critical > 0) {
353
+ return { grade: 'D', note: `${counts.critical} critical-severity ${pluralize('issue', counts.critical)}` };
354
+ }
355
+ if (counts.high > 0) {
356
+ return { grade: 'C', note: `${counts.high} high-severity ${pluralize('issue', counts.high)}` };
357
+ }
358
+ return null;
359
+ }
360
+
361
+ /**
362
+ * Maintainability uses a density-based grade (issues per KLOC) once the
363
+ * codebase is at least 5 KLOC. For smaller codebases, density is too noisy
364
+ * (one extra lint issue moves density by 1.0+), so we fall back to absolute
365
+ * counts — preventing tiny projects from being unfairly penalized.
366
+ *
367
+ * Severity escape hatch: a single high-severity maintainability finding
368
+ * (e.g., a 1500-line file) caps the grade at C; a critical caps at D.
369
+ * "Worst wins" — we take min of density-grade and severity-cap.
370
+ */
371
+ function gradeMaintainability(findings: Array<{ severity: string }>, totalLines: number): DimensionScore {
372
+ const counts = countSeverities(findings);
373
+ const kloc = Math.max(totalLines / 1000, 1.0);
374
+
375
+ if (counts.total === 0) {
376
+ return {
377
+ name: 'maintainability',
378
+ score: 100,
379
+ grade: 'A',
380
+ rationale: '0 maintainability findings',
381
+ available: true,
382
+ findingCount: 0,
383
+ worstSeverity: null,
384
+ };
385
+ }
386
+
387
+ const band = kloc < 5 ? maintainabilityByCount(counts.total) : maintainabilityByDensity(counts.total, kloc);
388
+ const severityCap = maintainabilityEscape(counts);
389
+ const useCap = severityCap && gradeIsWorse(severityCap.grade, band.grade);
390
+ const finalGrade = useCap ? severityCap.grade : band.grade;
391
+ const finalPosition = useCap ? 0.5 : band.position;
392
+ const rationale = useCap ? `${band.label}, ${severityCap.note}` : band.label;
393
+
394
+ return {
395
+ name: 'maintainability',
396
+ score: scoreInBand(finalGrade, finalPosition),
397
+ grade: finalGrade,
398
+ rationale,
399
+ available: true,
400
+ findingCount: counts.total,
401
+ worstSeverity: worstSeverity(counts),
402
+ };
403
+ }
404
+
405
+ // ============================================================================
406
+ // Grade Comparison Helpers
407
+ // ============================================================================
408
+
409
+ const GRADE_RANK: Record<Exclude<Grade, 'N/A'>, number> = {
410
+ F: 1,
411
+ D: 2,
412
+ C: 3,
413
+ B: 4,
414
+ A: 5,
415
+ };
416
+
417
+ function gradeIsWorse(a: Exclude<Grade, 'N/A'>, b: Exclude<Grade, 'N/A'>): boolean {
418
+ return GRADE_RANK[a] < GRADE_RANK[b];
419
+ }
420
+
421
+ function worstOf(grades: Array<Exclude<Grade, 'N/A'>>): Exclude<Grade, 'N/A'> {
422
+ let worst: Exclude<Grade, 'N/A'> = 'A';
423
+ for (const g of grades) {
424
+ if (gradeIsWorse(g, worst)) worst = g;
425
+ }
426
+ return worst;
427
+ }
428
+
429
+ // ============================================================================
430
+ // Misc Helpers
431
+ // ============================================================================
432
+
433
+ function pluralize(word: string, n: number): string {
434
+ return n === 1 ? word : `${word}s`;
435
+ }
436
+
437
+ function roundOne(n: number): number {
438
+ return Math.round(n * 10) / 10;
439
+ }
440
+
441
+ function dimensionDisplayName(name: DimensionName): string {
442
+ return name.charAt(0).toUpperCase() + name.slice(1);
443
+ }
444
+
445
+ function naDimension(name: DimensionName): DimensionScore {
446
+ return {
447
+ name,
448
+ score: 0,
449
+ grade: 'N/A',
450
+ rationale: 'No tools available to evaluate',
451
+ available: false,
452
+ findingCount: 0,
453
+ worstSeverity: null,
454
+ };
455
+ }
456
+
457
+ // ============================================================================
458
+ // Top-Level Entry Point
459
+ // ============================================================================
460
+
461
+ /**
462
+ * Compute the full multi-dimensional quality rating from the merged finding
463
+ * set. Callers can override availability in two ways:
464
+ * - `availableDimensions`: hard whitelist — only listed dims are graded.
465
+ * - `forceNA`: forces specific dims to N/A even if they would otherwise
466
+ * auto-detect as available. Use this when the underlying tools didn't
467
+ * run (e.g., no linter installed -> Maintainability has limited coverage).
468
+ *
469
+ * Default availability rules:
470
+ * - maintainability is always available (lint/format/length checks always run)
471
+ * - security/reliability are available iff at least one finding maps there
472
+ *
473
+ * Overall score uses min(avg, worst) so a single bad dimension caps the
474
+ * total — you cannot earn a great overall score by averaging away a hole.
475
+ */
476
+ function bucketByDimension(
477
+ findings: Array<{ severity: string; category: string }>,
478
+ ): {
479
+ security: Array<{ severity: string; category: string }>;
480
+ reliability: Array<{ severity: string; category: string }>;
481
+ maintainability: Array<{ severity: string; category: string }>;
482
+ } {
483
+ const security: Array<{ severity: string; category: string }> = [];
484
+ const reliability: Array<{ severity: string; category: string }> = [];
485
+ const maintainability: Array<{ severity: string; category: string }> = [];
486
+ for (const f of findings) {
487
+ const dim = categoryToDimension(f.category);
488
+ if (dim === 'security') security.push(f);
489
+ else if (dim === 'reliability') reliability.push(f);
490
+ else maintainability.push(f);
491
+ }
492
+ return { security, reliability, maintainability };
493
+ }
494
+
495
+ function isDimensionAvailable(
496
+ dim: DimensionName,
497
+ hasFindings: boolean,
498
+ options?: { availableDimensions?: Set<DimensionName>; forceNA?: Set<DimensionName> },
499
+ ): boolean {
500
+ if (options?.forceNA?.has(dim)) return false;
501
+ const explicit = options?.availableDimensions;
502
+ if (explicit) return explicit.has(dim);
503
+ // Auto-detect: maintainability always on, security/reliability iff findings exist.
504
+ return dim === 'maintainability' ? true : hasFindings;
505
+ }
506
+
507
+ function computeOverall(availableDims: DimensionScore[]): { grade: Grade; score: number } {
508
+ if (availableDims.length === 0) {
509
+ return { grade: 'N/A', score: 0 };
510
+ }
511
+ const grades = availableDims.map((d) => d.grade as Exclude<Grade, 'N/A'>);
512
+ const scores = availableDims.map((d) => d.score);
513
+ const avg = scores.reduce((s, n) => s + n, 0) / scores.length;
514
+ return {
515
+ grade: worstOf(grades),
516
+ score: Math.round(Math.min(avg, Math.min(...scores))),
517
+ };
518
+ }
519
+
520
+ export function computeQualityRating(
521
+ allFindings: Array<{ severity: string; category: string }>,
522
+ totalLines: number,
523
+ options?: { availableDimensions?: Set<DimensionName>; forceNA?: Set<DimensionName> },
524
+ ): QualityRating {
525
+ const buckets = bucketByDimension(allFindings);
526
+
527
+ const security = isDimensionAvailable('security', buckets.security.length > 0, options)
528
+ ? gradeSecurity(buckets.security)
529
+ : naDimension('security');
530
+ const reliability = isDimensionAvailable('reliability', buckets.reliability.length > 0, options)
531
+ ? gradeReliability(buckets.reliability)
532
+ : naDimension('reliability');
533
+ const maintainability = isDimensionAvailable('maintainability', true, options)
534
+ ? gradeMaintainability(buckets.maintainability, totalLines)
535
+ : naDimension('maintainability');
536
+
537
+ const dimensions: DimensionScore[] = [security, reliability, maintainability];
538
+ const availableDims = dimensions.filter((d) => d.available);
539
+ const overall = computeOverall(availableDims);
540
+
541
+ // Quality gate.
542
+ const qualityGate = computeQualityGate(security, reliability);
543
+
544
+ // Grade rationale.
545
+ const gradeRationale = computeGradeRationale(availableDims, overall.grade, allFindings.length);
546
+
547
+ return {
548
+ overall,
549
+ dimensions,
550
+ qualityGate,
551
+ gradeRationale,
552
+ };
553
+ }
554
+
555
+ // ============================================================================
556
+ // Quality Gate
557
+ // ============================================================================
558
+
559
+ /**
560
+ * The Quality Gate is a coarse PASS/FAIL signal layered on top of the grades.
561
+ * It only fires for the most user-actionable thresholds — any medium+ security
562
+ * finding, or any critical bug. N/A dimensions never trigger a fail (we don't
563
+ * fail on missing data).
564
+ */
565
+ function computeQualityGate(security: DimensionScore, reliability: DimensionScore): QualityGate {
566
+ const failingConditions: string[] = [];
567
+
568
+ if (security.available && (security.grade === 'C' || security.grade === 'D' || security.grade === 'F')) {
569
+ failingConditions.push(`Security grade ${security.grade} — ${security.rationale}`);
570
+ }
571
+ if (reliability.available && reliability.grade === 'F') {
572
+ failingConditions.push(`Reliability grade F — ${reliability.rationale}`);
573
+ }
574
+
575
+ return {
576
+ passed: failingConditions.length === 0,
577
+ failingConditions,
578
+ };
579
+ }
580
+
581
+ // ============================================================================
582
+ // Grade Rationale
583
+ // ============================================================================
584
+
585
+ function computeGradeRationale(
586
+ availableDims: DimensionScore[],
587
+ overallGrade: Grade,
588
+ totalFindingCount: number,
589
+ ): string {
590
+ if (totalFindingCount === 0) {
591
+ return 'Clean — no findings detected';
592
+ }
593
+ if (availableDims.length === 0 || overallGrade === 'N/A') {
594
+ return 'No dimensions available to grade';
595
+ }
596
+
597
+ // All available dimensions equal -> "consistent quality".
598
+ const firstGrade = availableDims[0].grade;
599
+ const allEqual = availableDims.every((d) => d.grade === firstGrade);
600
+ if (allEqual) {
601
+ return `All dimensions ${firstGrade} — consistent quality`;
602
+ }
603
+
604
+ // Find the dimension that pinned the overall grade (worst available).
605
+ const worstDim =
606
+ availableDims.find((d) => d.grade === overallGrade) ??
607
+ // Fallback shouldn't fire since overallGrade was derived from availableDims.
608
+ availableDims[0];
609
+
610
+ return `Capped at ${overallGrade} by ${dimensionDisplayName(worstDim.name)} (${worstDim.rationale})`;
611
+ }
@@ -1,5 +1,4 @@
1
1
  // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
- // Licensed under the MIT License. See LICENSE file for details.
3
2
 
4
3
  /**
5
4
  * Quality Handlers — WebSocket message router for quality scanning
@@ -173,6 +172,15 @@ async function handleSaveDirectories(
173
172
  }
174
173
 
175
174
  persistence.saveConfig(directories);
175
+
176
+ // Broadcast the updated set so every paired web (on any Fly instance)
177
+ // reflects the change. This is how Quality subdirectory tabs stay in
178
+ // sync across devices — the type is listed in the cross-instance
179
+ // set in `server/src/relay/handlers/clientHandlers.ts`.
180
+ ctx.broadcastToAll({
181
+ type: 'qualityDirectoriesUpdated',
182
+ data: { directories },
183
+ });
176
184
  } catch (error) {
177
185
  ctx.send(ws, {
178
186
  type: 'qualityError',
@@ -245,9 +253,11 @@ async function handleScan(
245
253
 
246
254
  const resultData = { path: reportPath, results };
247
255
  try {
248
- ctx.send(ws, { type: 'qualityScanResults', data: resultData });
256
+ // Broadcast so every device sees the new scan — the Quality view on
257
+ // another device otherwise stays stuck on the previous scan results.
258
+ ctx.broadcastToAll({ type: 'qualityScanResults', data: resultData });
249
259
  } catch {
250
- // WebSocket closed — save as pending for delivery on reconnect
260
+ // Broadcast failed — save as pending for delivery on reconnect
251
261
  persistence.addPendingResult({
252
262
  type: 'scanResults',
253
263
  path: reportPath,
@@ -288,7 +298,9 @@ async function handleInstallTools(
288
298
 
289
299
  const { tools, ecosystem } = await installTools(dirPath, toolNames);
290
300
 
291
- ctx.send(ws, {
301
+ // Broadcast so every device sees the install result (status of tools
302
+ // changes orchestra-wide once installed on the machine).
303
+ ctx.broadcastToAll({
292
304
  type: 'qualityInstallComplete',
293
305
  data: { path: reportPath, tools, ecosystem },
294
306
  });
@@ -1,5 +1,4 @@
1
1
  // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
- // Licensed under the MIT License. See LICENSE file for details.
3
2
 
4
3
  import { relative } from 'node:path';
5
4
  import { chunkFileList, filesByExt, runCommand, type SourceFile } from './quality-tools.js';