mstro-app 0.4.3 → 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 (306) hide show
  1. package/dist/server/cli/headless/claude-invoker-process.d.ts +11 -0
  2. package/dist/server/cli/headless/claude-invoker-process.d.ts.map +1 -0
  3. package/dist/server/cli/headless/claude-invoker-process.js +140 -0
  4. package/dist/server/cli/headless/claude-invoker-process.js.map +1 -0
  5. package/dist/server/cli/headless/claude-invoker-stall.d.ts +40 -0
  6. package/dist/server/cli/headless/claude-invoker-stall.d.ts.map +1 -0
  7. package/dist/server/cli/headless/claude-invoker-stall.js +98 -0
  8. package/dist/server/cli/headless/claude-invoker-stall.js.map +1 -0
  9. package/dist/server/cli/headless/claude-invoker-stream.d.ts +44 -0
  10. package/dist/server/cli/headless/claude-invoker-stream.d.ts.map +1 -0
  11. package/dist/server/cli/headless/claude-invoker-stream.js +276 -0
  12. package/dist/server/cli/headless/claude-invoker-stream.js.map +1 -0
  13. package/dist/server/cli/headless/claude-invoker-tools.d.ts +21 -0
  14. package/dist/server/cli/headless/claude-invoker-tools.d.ts.map +1 -0
  15. package/dist/server/cli/headless/claude-invoker-tools.js +137 -0
  16. package/dist/server/cli/headless/claude-invoker-tools.js.map +1 -0
  17. package/dist/server/cli/headless/claude-invoker.d.ts +6 -4
  18. package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -1
  19. package/dist/server/cli/headless/claude-invoker.js +10 -807
  20. package/dist/server/cli/headless/claude-invoker.js.map +1 -1
  21. package/dist/server/cli/headless/haiku-assessments.d.ts +62 -0
  22. package/dist/server/cli/headless/haiku-assessments.d.ts.map +1 -0
  23. package/dist/server/cli/headless/haiku-assessments.js +281 -0
  24. package/dist/server/cli/headless/haiku-assessments.js.map +1 -0
  25. package/dist/server/cli/headless/headless-logger.d.ts +3 -2
  26. package/dist/server/cli/headless/headless-logger.d.ts.map +1 -1
  27. package/dist/server/cli/headless/headless-logger.js +28 -5
  28. package/dist/server/cli/headless/headless-logger.js.map +1 -1
  29. package/dist/server/cli/headless/native-timeout-detector.d.ts +44 -0
  30. package/dist/server/cli/headless/native-timeout-detector.d.ts.map +1 -0
  31. package/dist/server/cli/headless/native-timeout-detector.js +99 -0
  32. package/dist/server/cli/headless/native-timeout-detector.js.map +1 -0
  33. package/dist/server/cli/headless/stall-assessor.d.ts +2 -110
  34. package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
  35. package/dist/server/cli/headless/stall-assessor.js +65 -457
  36. package/dist/server/cli/headless/stall-assessor.js.map +1 -1
  37. package/dist/server/cli/improvisation-attachments.d.ts +21 -0
  38. package/dist/server/cli/improvisation-attachments.d.ts.map +1 -0
  39. package/dist/server/cli/improvisation-attachments.js +116 -0
  40. package/dist/server/cli/improvisation-attachments.js.map +1 -0
  41. package/dist/server/cli/improvisation-retry.d.ts +52 -0
  42. package/dist/server/cli/improvisation-retry.d.ts.map +1 -0
  43. package/dist/server/cli/improvisation-retry.js +434 -0
  44. package/dist/server/cli/improvisation-retry.js.map +1 -0
  45. package/dist/server/cli/improvisation-session-manager.d.ts +10 -266
  46. package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
  47. package/dist/server/cli/improvisation-session-manager.js +117 -1079
  48. package/dist/server/cli/improvisation-session-manager.js.map +1 -1
  49. package/dist/server/cli/improvisation-types.d.ts +86 -0
  50. package/dist/server/cli/improvisation-types.d.ts.map +1 -0
  51. package/dist/server/cli/improvisation-types.js +10 -0
  52. package/dist/server/cli/improvisation-types.js.map +1 -0
  53. package/dist/server/cli/prompt-builders.d.ts +68 -0
  54. package/dist/server/cli/prompt-builders.d.ts.map +1 -0
  55. package/dist/server/cli/prompt-builders.js +312 -0
  56. package/dist/server/cli/prompt-builders.js.map +1 -0
  57. package/dist/server/index.js +33 -212
  58. package/dist/server/index.js.map +1 -1
  59. package/dist/server/mcp/bouncer-haiku.d.ts +10 -0
  60. package/dist/server/mcp/bouncer-haiku.d.ts.map +1 -0
  61. package/dist/server/mcp/bouncer-haiku.js +152 -0
  62. package/dist/server/mcp/bouncer-haiku.js.map +1 -0
  63. package/dist/server/mcp/bouncer-integration.d.ts +3 -4
  64. package/dist/server/mcp/bouncer-integration.d.ts.map +1 -1
  65. package/dist/server/mcp/bouncer-integration.js +50 -196
  66. package/dist/server/mcp/bouncer-integration.js.map +1 -1
  67. package/dist/server/mcp/security-analysis.d.ts +38 -0
  68. package/dist/server/mcp/security-analysis.d.ts.map +1 -0
  69. package/dist/server/mcp/security-analysis.js +183 -0
  70. package/dist/server/mcp/security-analysis.js.map +1 -0
  71. package/dist/server/mcp/security-audit.d.ts +1 -1
  72. package/dist/server/mcp/security-audit.d.ts.map +1 -1
  73. package/dist/server/mcp/security-patterns.d.ts +1 -25
  74. package/dist/server/mcp/security-patterns.d.ts.map +1 -1
  75. package/dist/server/mcp/security-patterns.js +55 -260
  76. package/dist/server/mcp/security-patterns.js.map +1 -1
  77. package/dist/server/server-setup.d.ts +22 -0
  78. package/dist/server/server-setup.d.ts.map +1 -0
  79. package/dist/server/server-setup.js +101 -0
  80. package/dist/server/server-setup.js.map +1 -0
  81. package/dist/server/services/file-explorer-ops.d.ts +24 -0
  82. package/dist/server/services/file-explorer-ops.d.ts.map +1 -0
  83. package/dist/server/services/file-explorer-ops.js +211 -0
  84. package/dist/server/services/file-explorer-ops.js.map +1 -0
  85. package/dist/server/services/files.d.ts +2 -85
  86. package/dist/server/services/files.d.ts.map +1 -1
  87. package/dist/server/services/files.js +7 -427
  88. package/dist/server/services/files.js.map +1 -1
  89. package/dist/server/services/plan/composer.d.ts.map +1 -1
  90. package/dist/server/services/plan/composer.js +2 -1
  91. package/dist/server/services/plan/composer.js.map +1 -1
  92. package/dist/server/services/plan/executor.d.ts.map +1 -1
  93. package/dist/server/services/plan/executor.js +3 -1
  94. package/dist/server/services/plan/executor.js.map +1 -1
  95. package/dist/server/services/plan/parser-core.d.ts +20 -0
  96. package/dist/server/services/plan/parser-core.d.ts.map +1 -0
  97. package/dist/server/services/plan/parser-core.js +350 -0
  98. package/dist/server/services/plan/parser-core.js.map +1 -0
  99. package/dist/server/services/plan/parser-migration.d.ts +5 -0
  100. package/dist/server/services/plan/parser-migration.d.ts.map +1 -0
  101. package/dist/server/services/plan/parser-migration.js +124 -0
  102. package/dist/server/services/plan/parser-migration.js.map +1 -0
  103. package/dist/server/services/plan/parser.d.ts +0 -8
  104. package/dist/server/services/plan/parser.d.ts.map +1 -1
  105. package/dist/server/services/plan/parser.js +50 -569
  106. package/dist/server/services/plan/parser.js.map +1 -1
  107. package/dist/server/services/plan/review-gate.d.ts +2 -0
  108. package/dist/server/services/plan/review-gate.d.ts.map +1 -1
  109. package/dist/server/services/plan/review-gate.js +2 -2
  110. package/dist/server/services/plan/review-gate.js.map +1 -1
  111. package/dist/server/services/plan/types.d.ts +2 -0
  112. package/dist/server/services/plan/types.d.ts.map +1 -1
  113. package/dist/server/services/platform-credentials.d.ts +24 -0
  114. package/dist/server/services/platform-credentials.d.ts.map +1 -0
  115. package/dist/server/services/platform-credentials.js +68 -0
  116. package/dist/server/services/platform-credentials.js.map +1 -0
  117. package/dist/server/services/platform.d.ts +1 -31
  118. package/dist/server/services/platform.d.ts.map +1 -1
  119. package/dist/server/services/platform.js +10 -119
  120. package/dist/server/services/platform.js.map +1 -1
  121. package/dist/server/services/terminal/pty-manager.d.ts +7 -97
  122. package/dist/server/services/terminal/pty-manager.d.ts.map +1 -1
  123. package/dist/server/services/terminal/pty-manager.js +53 -266
  124. package/dist/server/services/terminal/pty-manager.js.map +1 -1
  125. package/dist/server/services/terminal/pty-utils.d.ts +57 -0
  126. package/dist/server/services/terminal/pty-utils.d.ts.map +1 -0
  127. package/dist/server/services/terminal/pty-utils.js +141 -0
  128. package/dist/server/services/terminal/pty-utils.js.map +1 -0
  129. package/dist/server/services/websocket/file-definition-handlers.d.ts +4 -0
  130. package/dist/server/services/websocket/file-definition-handlers.d.ts.map +1 -0
  131. package/dist/server/services/websocket/file-definition-handlers.js +153 -0
  132. package/dist/server/services/websocket/file-definition-handlers.js.map +1 -0
  133. package/dist/server/services/websocket/file-explorer-handlers.d.ts.map +1 -1
  134. package/dist/server/services/websocket/file-explorer-handlers.js +52 -391
  135. package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -1
  136. package/dist/server/services/websocket/file-search-handlers.d.ts +5 -0
  137. package/dist/server/services/websocket/file-search-handlers.d.ts.map +1 -0
  138. package/dist/server/services/websocket/file-search-handlers.js +238 -0
  139. package/dist/server/services/websocket/file-search-handlers.js.map +1 -0
  140. package/dist/server/services/websocket/file-utils.js +3 -3
  141. package/dist/server/services/websocket/file-utils.js.map +1 -1
  142. package/dist/server/services/websocket/git-branch-handlers.d.ts +7 -0
  143. package/dist/server/services/websocket/git-branch-handlers.d.ts.map +1 -0
  144. package/dist/server/services/websocket/git-branch-handlers.js +110 -0
  145. package/dist/server/services/websocket/git-branch-handlers.js.map +1 -0
  146. package/dist/server/services/websocket/git-diff-handlers.d.ts +6 -0
  147. package/dist/server/services/websocket/git-diff-handlers.d.ts.map +1 -0
  148. package/dist/server/services/websocket/git-diff-handlers.js +123 -0
  149. package/dist/server/services/websocket/git-diff-handlers.js.map +1 -0
  150. package/dist/server/services/websocket/git-handlers.d.ts +2 -31
  151. package/dist/server/services/websocket/git-handlers.d.ts.map +1 -1
  152. package/dist/server/services/websocket/git-handlers.js +35 -541
  153. package/dist/server/services/websocket/git-handlers.js.map +1 -1
  154. package/dist/server/services/websocket/git-log-handlers.d.ts +6 -0
  155. package/dist/server/services/websocket/git-log-handlers.d.ts.map +1 -0
  156. package/dist/server/services/websocket/git-log-handlers.js +128 -0
  157. package/dist/server/services/websocket/git-log-handlers.js.map +1 -0
  158. package/dist/server/services/websocket/git-pr-handlers.d.ts.map +1 -1
  159. package/dist/server/services/websocket/git-pr-handlers.js +13 -53
  160. package/dist/server/services/websocket/git-pr-handlers.js.map +1 -1
  161. package/dist/server/services/websocket/git-tag-handlers.d.ts +6 -0
  162. package/dist/server/services/websocket/git-tag-handlers.d.ts.map +1 -0
  163. package/dist/server/services/websocket/git-tag-handlers.js +76 -0
  164. package/dist/server/services/websocket/git-tag-handlers.js.map +1 -0
  165. package/dist/server/services/websocket/git-utils.d.ts +43 -0
  166. package/dist/server/services/websocket/git-utils.d.ts.map +1 -0
  167. package/dist/server/services/websocket/git-utils.js +201 -0
  168. package/dist/server/services/websocket/git-utils.js.map +1 -0
  169. package/dist/server/services/websocket/handler.d.ts +2 -0
  170. package/dist/server/services/websocket/handler.d.ts.map +1 -1
  171. package/dist/server/services/websocket/handler.js +37 -126
  172. package/dist/server/services/websocket/handler.js.map +1 -1
  173. package/dist/server/services/websocket/plan-board-handlers.d.ts +11 -0
  174. package/dist/server/services/websocket/plan-board-handlers.d.ts.map +1 -0
  175. package/dist/server/services/websocket/plan-board-handlers.js +218 -0
  176. package/dist/server/services/websocket/plan-board-handlers.js.map +1 -0
  177. package/dist/server/services/websocket/plan-execution-handlers.d.ts +9 -0
  178. package/dist/server/services/websocket/plan-execution-handlers.d.ts.map +1 -0
  179. package/dist/server/services/websocket/plan-execution-handlers.js +142 -0
  180. package/dist/server/services/websocket/plan-execution-handlers.js.map +1 -0
  181. package/dist/server/services/websocket/plan-handlers.d.ts +7 -2
  182. package/dist/server/services/websocket/plan-handlers.d.ts.map +1 -1
  183. package/dist/server/services/websocket/plan-handlers.js +6 -925
  184. package/dist/server/services/websocket/plan-handlers.js.map +1 -1
  185. package/dist/server/services/websocket/plan-helpers.d.ts +19 -0
  186. package/dist/server/services/websocket/plan-helpers.d.ts.map +1 -0
  187. package/dist/server/services/websocket/plan-helpers.js +199 -0
  188. package/dist/server/services/websocket/plan-helpers.js.map +1 -0
  189. package/dist/server/services/websocket/plan-issue-handlers.d.ts +12 -0
  190. package/dist/server/services/websocket/plan-issue-handlers.d.ts.map +1 -0
  191. package/dist/server/services/websocket/plan-issue-handlers.js +162 -0
  192. package/dist/server/services/websocket/plan-issue-handlers.js.map +1 -0
  193. package/dist/server/services/websocket/plan-sprint-handlers.d.ts +7 -0
  194. package/dist/server/services/websocket/plan-sprint-handlers.d.ts.map +1 -0
  195. package/dist/server/services/websocket/plan-sprint-handlers.js +206 -0
  196. package/dist/server/services/websocket/plan-sprint-handlers.js.map +1 -0
  197. package/dist/server/services/websocket/quality-complexity.d.ts +14 -0
  198. package/dist/server/services/websocket/quality-complexity.d.ts.map +1 -0
  199. package/dist/server/services/websocket/quality-complexity.js +262 -0
  200. package/dist/server/services/websocket/quality-complexity.js.map +1 -0
  201. package/dist/server/services/websocket/quality-fix-agent.d.ts +16 -0
  202. package/dist/server/services/websocket/quality-fix-agent.d.ts.map +1 -0
  203. package/dist/server/services/websocket/quality-fix-agent.js +140 -0
  204. package/dist/server/services/websocket/quality-fix-agent.js.map +1 -0
  205. package/dist/server/services/websocket/quality-handlers.d.ts.map +1 -1
  206. package/dist/server/services/websocket/quality-handlers.js +34 -346
  207. package/dist/server/services/websocket/quality-handlers.js.map +1 -1
  208. package/dist/server/services/websocket/quality-linting.d.ts +9 -0
  209. package/dist/server/services/websocket/quality-linting.d.ts.map +1 -0
  210. package/dist/server/services/websocket/quality-linting.js +178 -0
  211. package/dist/server/services/websocket/quality-linting.js.map +1 -0
  212. package/dist/server/services/websocket/quality-review-agent.d.ts +19 -0
  213. package/dist/server/services/websocket/quality-review-agent.d.ts.map +1 -0
  214. package/dist/server/services/websocket/quality-review-agent.js +206 -0
  215. package/dist/server/services/websocket/quality-review-agent.js.map +1 -0
  216. package/dist/server/services/websocket/quality-service.d.ts +3 -51
  217. package/dist/server/services/websocket/quality-service.d.ts.map +1 -1
  218. package/dist/server/services/websocket/quality-service.js +9 -651
  219. package/dist/server/services/websocket/quality-service.js.map +1 -1
  220. package/dist/server/services/websocket/quality-tools.d.ts +23 -0
  221. package/dist/server/services/websocket/quality-tools.d.ts.map +1 -0
  222. package/dist/server/services/websocket/quality-tools.js +208 -0
  223. package/dist/server/services/websocket/quality-tools.js.map +1 -0
  224. package/dist/server/services/websocket/quality-types.d.ts +59 -0
  225. package/dist/server/services/websocket/quality-types.d.ts.map +1 -0
  226. package/dist/server/services/websocket/quality-types.js +101 -0
  227. package/dist/server/services/websocket/quality-types.js.map +1 -0
  228. package/dist/server/services/websocket/session-handlers.d.ts +3 -4
  229. package/dist/server/services/websocket/session-handlers.d.ts.map +1 -1
  230. package/dist/server/services/websocket/session-handlers.js +3 -378
  231. package/dist/server/services/websocket/session-handlers.js.map +1 -1
  232. package/dist/server/services/websocket/session-history.d.ts +4 -0
  233. package/dist/server/services/websocket/session-history.d.ts.map +1 -0
  234. package/dist/server/services/websocket/session-history.js +208 -0
  235. package/dist/server/services/websocket/session-history.js.map +1 -0
  236. package/dist/server/services/websocket/session-initialization.d.ts +5 -0
  237. package/dist/server/services/websocket/session-initialization.d.ts.map +1 -0
  238. package/dist/server/services/websocket/session-initialization.js +163 -0
  239. package/dist/server/services/websocket/session-initialization.js.map +1 -0
  240. package/dist/server/services/websocket/types.d.ts +12 -2
  241. package/dist/server/services/websocket/types.d.ts.map +1 -1
  242. package/package.json +1 -1
  243. package/server/cli/headless/claude-invoker-process.ts +204 -0
  244. package/server/cli/headless/claude-invoker-stall.ts +164 -0
  245. package/server/cli/headless/claude-invoker-stream.ts +353 -0
  246. package/server/cli/headless/claude-invoker-tools.ts +187 -0
  247. package/server/cli/headless/claude-invoker.ts +15 -1096
  248. package/server/cli/headless/haiku-assessments.ts +365 -0
  249. package/server/cli/headless/headless-logger.ts +26 -5
  250. package/server/cli/headless/native-timeout-detector.ts +117 -0
  251. package/server/cli/headless/stall-assessor.ts +65 -618
  252. package/server/cli/improvisation-attachments.ts +148 -0
  253. package/server/cli/improvisation-retry.ts +602 -0
  254. package/server/cli/improvisation-session-manager.ts +140 -1349
  255. package/server/cli/improvisation-types.ts +98 -0
  256. package/server/cli/prompt-builders.ts +370 -0
  257. package/server/index.ts +35 -246
  258. package/server/mcp/bouncer-haiku.ts +182 -0
  259. package/server/mcp/bouncer-integration.ts +87 -248
  260. package/server/mcp/security-analysis.ts +217 -0
  261. package/server/mcp/security-audit.ts +1 -1
  262. package/server/mcp/security-patterns.ts +60 -283
  263. package/server/server-setup.ts +114 -0
  264. package/server/services/file-explorer-ops.ts +293 -0
  265. package/server/services/files.ts +20 -532
  266. package/server/services/plan/composer.ts +2 -1
  267. package/server/services/plan/executor.ts +3 -1
  268. package/server/services/plan/parser-core.ts +406 -0
  269. package/server/services/plan/parser-migration.ts +128 -0
  270. package/server/services/plan/parser.ts +52 -620
  271. package/server/services/plan/review-gate.ts +4 -2
  272. package/server/services/plan/types.ts +2 -0
  273. package/server/services/platform-credentials.ts +83 -0
  274. package/server/services/platform.ts +15 -141
  275. package/server/services/terminal/pty-manager.ts +66 -313
  276. package/server/services/terminal/pty-utils.ts +176 -0
  277. package/server/services/websocket/file-definition-handlers.ts +165 -0
  278. package/server/services/websocket/file-explorer-handlers.ts +37 -452
  279. package/server/services/websocket/file-search-handlers.ts +291 -0
  280. package/server/services/websocket/file-utils.ts +3 -3
  281. package/server/services/websocket/git-branch-handlers.ts +130 -0
  282. package/server/services/websocket/git-diff-handlers.ts +140 -0
  283. package/server/services/websocket/git-handlers.ts +40 -625
  284. package/server/services/websocket/git-log-handlers.ts +149 -0
  285. package/server/services/websocket/git-pr-handlers.ts +17 -62
  286. package/server/services/websocket/git-tag-handlers.ts +91 -0
  287. package/server/services/websocket/git-utils.ts +230 -0
  288. package/server/services/websocket/handler.ts +39 -126
  289. package/server/services/websocket/plan-board-handlers.ts +277 -0
  290. package/server/services/websocket/plan-execution-handlers.ts +184 -0
  291. package/server/services/websocket/plan-handlers.ts +8 -1114
  292. package/server/services/websocket/plan-helpers.ts +215 -0
  293. package/server/services/websocket/plan-issue-handlers.ts +204 -0
  294. package/server/services/websocket/plan-sprint-handlers.ts +252 -0
  295. package/server/services/websocket/quality-complexity.ts +294 -0
  296. package/server/services/websocket/quality-fix-agent.ts +181 -0
  297. package/server/services/websocket/quality-handlers.ts +36 -404
  298. package/server/services/websocket/quality-linting.ts +187 -0
  299. package/server/services/websocket/quality-review-agent.ts +246 -0
  300. package/server/services/websocket/quality-service.ts +11 -762
  301. package/server/services/websocket/quality-tools.ts +209 -0
  302. package/server/services/websocket/quality-types.ts +169 -0
  303. package/server/services/websocket/session-handlers.ts +5 -437
  304. package/server/services/websocket/session-history.ts +222 -0
  305. package/server/services/websocket/session-initialization.ts +209 -0
  306. package/server/services/websocket/types.ts +17 -0
@@ -29,6 +29,8 @@ export interface ReviewIssueOptions {
29
29
  pmDir: string;
30
30
  outputPath: string;
31
31
  onOutput?: (text: string) => void;
32
+ /** Board-scoped log directory for execution logs. Falls back to global ~/.mstro/logs/headless/ */
33
+ logDir?: string;
32
34
  }
33
35
 
34
36
  /**
@@ -36,7 +38,7 @@ export interface ReviewIssueOptions {
36
38
  * Returns auto-pass on infrastructure failures to avoid blocking execution.
37
39
  */
38
40
  export async function reviewIssue(options: ReviewIssueOptions): Promise<ReviewResult> {
39
- const { workingDir, issue, pmDir, outputPath, onOutput } = options;
41
+ const { workingDir, issue, pmDir, outputPath, onOutput, logDir } = options;
40
42
  const isCodeTask = issue.filesToModify.length > 0;
41
43
  const issueType: ReviewResult['issueType'] = isCodeTask ? 'code' : 'non-code';
42
44
 
@@ -53,7 +55,7 @@ export async function reviewIssue(options: ReviewIssueOptions): Promise<ReviewRe
53
55
  outputCallback: onOutput ? (text: string) => onOutput(`Review: ${text}`) : undefined,
54
56
  });
55
57
 
56
- const result = await runWithFileLogger('pm-review', () => runner.run());
58
+ const result = await runWithFileLogger('pm-review', () => runner.run(), logDir);
57
59
 
58
60
  if (result.completed && result.assistantResponse) {
59
61
  return parseReviewOutput(issue.id, issueType, result.assistantResponse);
@@ -226,6 +226,8 @@ export interface BoardArtifacts {
226
226
  progressLog: string;
227
227
  outputFiles: string[];
228
228
  reviewResults: ReviewResult[];
229
+ /** Log file names from boards/BOARD-NNN/logs/ (wave execution + review logs) */
230
+ executionLogs: string[];
229
231
  }
230
232
 
231
233
  /** @deprecated Use BoardArtifacts — kept for migration compatibility */
@@ -0,0 +1,83 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file for details.
3
+
4
+ /**
5
+ * Platform Credentials — Token management for device authentication.
6
+ *
7
+ * Reads/writes credentials from ~/.mstro/credentials.json and handles
8
+ * periodic token refresh with the platform server.
9
+ */
10
+
11
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs'
12
+ import { homedir } from 'node:os'
13
+ import { join } from 'node:path'
14
+ import { MSTRO_ROOT } from '../utils/paths.js'
15
+
16
+ // Read CLI version from package.json once at import time
17
+ export const CLI_VERSION = (() => {
18
+ try {
19
+ const pkg = JSON.parse(readFileSync(join(MSTRO_ROOT, 'package.json'), 'utf-8'))
20
+ return pkg.version || '0.0.0'
21
+ } catch {
22
+ return '0.0.0'
23
+ }
24
+ })()
25
+
26
+ const MSTRO_DIR = join(homedir(), '.mstro')
27
+ const CREDENTIALS_FILE = join(MSTRO_DIR, 'credentials.json')
28
+
29
+ /** Refresh token every 30 days */
30
+ export const TOKEN_REFRESH_INTERVAL_MS = 30 * 24 * 60 * 60 * 1000
31
+
32
+ export interface StoredCredentials {
33
+ token: string
34
+ userId: string
35
+ email: string
36
+ name?: string
37
+ clientId: string
38
+ lastRefreshedAt?: string
39
+ }
40
+
41
+ /**
42
+ * Get stored credentials from ~/.mstro/credentials.json
43
+ */
44
+ export function getCredentials(): StoredCredentials | null {
45
+ if (!existsSync(CREDENTIALS_FILE)) {
46
+ return null
47
+ }
48
+ try {
49
+ const content = readFileSync(CREDENTIALS_FILE, 'utf-8')
50
+ const creds = JSON.parse(content)
51
+ if (creds.token && creds.userId && creds.email) {
52
+ return creds
53
+ }
54
+ return null
55
+ } catch {
56
+ return null
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Update stored credentials (for token refresh)
62
+ */
63
+ export function updateCredentials(updates: Partial<StoredCredentials>): void {
64
+ const creds = getCredentials()
65
+ if (!creds) return
66
+
67
+ writeFileSync(CREDENTIALS_FILE, JSON.stringify({ ...creds, ...updates }, null, 2), {
68
+ mode: 0o600
69
+ })
70
+ }
71
+
72
+ /**
73
+ * Check if token should be refreshed
74
+ */
75
+ export function shouldRefreshToken(creds: StoredCredentials): boolean {
76
+ if (!creds.lastRefreshedAt) {
77
+ return true
78
+ }
79
+
80
+ const lastRefreshed = new Date(creds.lastRefreshedAt).getTime()
81
+ const now = Date.now()
82
+ return now - lastRefreshed > TOKEN_REFRESH_INTERVAL_MS
83
+ }
@@ -7,92 +7,23 @@
7
7
  * Handles WebSocket connection to the Mstro platform.
8
8
  * Requires token-based authentication from `mstro login`.
9
9
  *
10
- * Flow:
11
- * 1. Client reads token from ~/.mstro/credentials.json
12
- * 2. Client connects to platform WebSocket with auth token
13
- * 3. Platform validates token and auto-pairs to user's account
14
- * 4. Client becomes an "orchestra" visible in user's web dashboard
10
+ * Credential management lives in platform-credentials.ts.
15
11
  */
16
12
 
17
- import { existsSync, readFileSync, writeFileSync } from 'node:fs'
18
- import { arch, homedir, hostname, type } from 'node:os'
19
- import { basename, join } from 'node:path'
13
+ import { arch, hostname, type } from 'node:os'
14
+ import { basename } from 'node:path'
20
15
  import { AnalyticsEvents, trackEvent } from './analytics.js'
21
16
  import { getClientId } from './client-id.js'
17
+ import {
18
+ CLI_VERSION,
19
+ getCredentials,
20
+ shouldRefreshToken,
21
+ updateCredentials,
22
+ } from './platform-credentials.js'
22
23
  import { captureException } from './sentry.js'
23
24
 
24
- // Read CLI version from package.json once at import time
25
- const CLI_VERSION = (() => {
26
- try {
27
- const pkg = JSON.parse(readFileSync(join(import.meta.dirname || '.', '..', 'package.json'), 'utf-8'))
28
- return pkg.version || '0.0.0'
29
- } catch {
30
- return '0.0.0'
31
- }
32
- })()
33
-
34
- const MSTRO_DIR = join(homedir(), '.mstro')
35
- const CREDENTIALS_FILE = join(MSTRO_DIR, 'credentials.json')
36
-
37
- // Refresh token every 30 days
38
- const TOKEN_REFRESH_INTERVAL_MS = 30 * 24 * 60 * 60 * 1000
39
-
40
- interface StoredCredentials {
41
- token: string
42
- userId: string
43
- email: string
44
- name?: string
45
- clientId: string
46
- lastRefreshedAt?: string
47
- }
48
-
49
- /**
50
- * Get stored credentials from ~/.mstro/credentials.json
51
- */
52
- function getCredentials(): StoredCredentials | null {
53
- if (!existsSync(CREDENTIALS_FILE)) {
54
- return null
55
- }
56
- try {
57
- const content = readFileSync(CREDENTIALS_FILE, 'utf-8')
58
- const creds = JSON.parse(content)
59
- if (creds.token && creds.userId && creds.email) {
60
- return creds
61
- }
62
- return null
63
- } catch {
64
- return null
65
- }
66
- }
67
-
68
- /**
69
- * Update stored credentials (for token refresh)
70
- */
71
- function updateCredentials(updates: Partial<StoredCredentials>): void {
72
- const creds = getCredentials()
73
- if (!creds) return
74
-
75
- writeFileSync(CREDENTIALS_FILE, JSON.stringify({ ...creds, ...updates }, null, 2), {
76
- mode: 0o600
77
- })
78
- }
79
-
80
- /**
81
- * Check if token should be refreshed
82
- */
83
- function shouldRefreshToken(creds: StoredCredentials): boolean {
84
- if (!creds.lastRefreshedAt) {
85
- return true // Never refreshed
86
- }
87
-
88
- const lastRefreshed = new Date(creds.lastRefreshedAt).getTime()
89
- const now = Date.now()
90
- return now - lastRefreshed > TOKEN_REFRESH_INTERVAL_MS
91
- }
92
-
93
25
  /**
94
26
  * Get machine identification string
95
- * Format: "hostname @ node-vX.X.X platform (arch)"
96
27
  * Example: "Jessica @ node-v22.21.1 linux (arm64)"
97
28
  */
98
29
  export function getMachineIdentifier(): string {
@@ -124,9 +55,6 @@ interface ConnectionCallbacks {
124
55
  onRelayedMessage?: (message: unknown) => void
125
56
  }
126
57
 
127
- /**
128
- * Platform WebSocket connection with token-based authentication
129
- */
130
58
  /** Number of missed pongs before treating connection as dead */
131
59
  const MAX_MISSED_PONGS = 2
132
60
 
@@ -144,6 +72,7 @@ export class PlatformConnection {
144
72
  private tokenRefreshInterval: ReturnType<typeof setInterval> | null = null
145
73
  private heartbeatInterval: ReturnType<typeof setInterval> | null = null
146
74
  private missedPongs = 0
75
+ private readonly startedAt: string
147
76
 
148
77
  constructor(
149
78
  workingDirectory: string,
@@ -153,16 +82,12 @@ export class PlatformConnection {
153
82
  this.workingDirectory = workingDirectory
154
83
  this.platformUrl = platformUrl || DEFAULT_PLATFORM_URL
155
84
  this.callbacks = callbacks
85
+ this.startedAt = new Date().toISOString()
156
86
  }
157
87
 
158
- /**
159
- * Refresh the device token if needed
160
- */
161
88
  private async maybeRefreshToken(): Promise<void> {
162
89
  const creds = getCredentials()
163
- if (!creds || !shouldRefreshToken(creds)) {
164
- return
165
- }
90
+ if (!creds || !shouldRefreshToken(creds)) return
166
91
 
167
92
  try {
168
93
  const response = await fetch(`${this.platformUrl}/api/auth/device/refresh`, {
@@ -187,25 +112,14 @@ export class PlatformConnection {
187
112
  }
188
113
  }
189
114
 
190
- /**
191
- * Start periodic token refresh check
192
- */
193
115
  private startTokenRefreshCheck(): void {
194
- // Check every 24 hours
195
116
  this.tokenRefreshInterval = setInterval(() => {
196
117
  this.maybeRefreshToken()
197
118
  }, 24 * 60 * 60 * 1000)
198
119
  }
199
120
 
200
- /**
201
- * Start heartbeat to keep connection alive and refresh server-side TTL.
202
- * Tracks missed pongs — if the server doesn't respond to MAX_MISSED_PONGS
203
- * consecutive pings, the connection is considered dead and force-closed
204
- * to trigger reconnection.
205
- */
206
121
  private startHeartbeat(): void {
207
122
  this.missedPongs = 0
208
- // Send ping every 2 minutes (server TTL is 5 minutes)
209
123
  this.heartbeatInterval = setInterval(() => this.heartbeatTick(), 2 * 60 * 1000)
210
124
  }
211
125
 
@@ -227,9 +141,6 @@ export class PlatformConnection {
227
141
  }
228
142
  }
229
143
 
230
- /**
231
- * Stop heartbeat
232
- */
233
144
  private stopHeartbeat(): void {
234
145
  if (this.heartbeatInterval) {
235
146
  clearInterval(this.heartbeatInterval)
@@ -237,9 +148,6 @@ export class PlatformConnection {
237
148
  }
238
149
  }
239
150
 
240
- /**
241
- * Stop periodic token refresh check
242
- */
243
151
  private stopTokenRefreshCheck(): void {
244
152
  if (this.tokenRefreshInterval) {
245
153
  clearInterval(this.tokenRefreshInterval)
@@ -247,9 +155,6 @@ export class PlatformConnection {
247
155
  }
248
156
  }
249
157
 
250
- /**
251
- * Connect to platform WebSocket
252
- */
253
158
  connect(): void {
254
159
  this.isIntentionallyClosed = false
255
160
  const name = basename(this.workingDirectory)
@@ -260,7 +165,6 @@ export class PlatformConnection {
260
165
  const osType = type().toLowerCase()
261
166
  const cpuArch = arch()
262
167
 
263
- // Get auth token from credentials
264
168
  const credentials = getCredentials()
265
169
  const authToken = credentials?.token
266
170
 
@@ -270,8 +174,6 @@ export class PlatformConnection {
270
174
  return
271
175
  }
272
176
 
273
- // Build URL params WITHOUT the auth token — token is sent post-connection
274
- // to avoid leaking it in proxy logs, browser history, and server access logs
275
177
  const params = new URLSearchParams({
276
178
  name,
277
179
  workingDirectory: this.workingDirectory,
@@ -282,7 +184,8 @@ export class PlatformConnection {
282
184
  osType,
283
185
  cpuArch,
284
186
  cliVersion: CLI_VERSION,
285
- capabilities: JSON.stringify({})
187
+ capabilities: JSON.stringify({}),
188
+ startedAt: this.startedAt,
286
189
  })
287
190
 
288
191
  const wsUrl = `${this.platformUrl.replace(/^http/, 'ws')}/ws/client?${params}`
@@ -297,10 +200,9 @@ export class PlatformConnection {
297
200
  return
298
201
  }
299
202
 
300
- // Connection timeout - if not connected within 10 seconds, show helpful error
301
203
  const connectionTimeout = setTimeout(() => {
302
204
  const state = this.ws?.readyState
303
- if (this.ws && (state === 0 || state === undefined)) { // CONNECTING or unknown
205
+ if (this.ws && (state === 0 || state === undefined)) {
304
206
  console.error('\n❌ Connection timeout. The platform may have rejected your credentials.')
305
207
  console.error(' Run `mstro login --force` to re-authenticate.\n')
306
208
  this.ws.close()
@@ -310,14 +212,8 @@ export class PlatformConnection {
310
212
 
311
213
  this.ws.onopen = () => {
312
214
  clearTimeout(connectionTimeout)
313
- // Platform WebSocket open — auth will follow
314
-
315
- // Send auth token as first message instead of URL param
316
215
  this.ws!.send(JSON.stringify({ type: 'auth', token: authToken }))
317
-
318
- // Check if token needs refresh on connect
319
216
  this.maybeRefreshToken()
320
- // Start periodic refresh checks
321
217
  this.startTokenRefreshCheck()
322
218
  this.reconnectAttempts = 0
323
219
  trackEvent(AnalyticsEvents.PLATFORM_CONNECTED)
@@ -332,7 +228,6 @@ export class PlatformConnection {
332
228
  }
333
229
  }
334
230
 
335
- // Track if we ever successfully connected (received 'paired' message)
336
231
  let everConnected = false
337
232
  const originalOnConnected = this.callbacks.onConnected
338
233
  this.callbacks.onConnected = (connectionId) => {
@@ -341,12 +236,10 @@ export class PlatformConnection {
341
236
  }
342
237
 
343
238
  this.ws.onclose = (event) => {
344
- // Stop heartbeat on any close
345
239
  this.stopHeartbeat()
346
240
  this.isConnected = false
347
241
 
348
242
  if (!this.isIntentionallyClosed) {
349
- // Check if we were rejected due to auth (code 4001 or 1006 before ever connecting)
350
243
  const isAuthFailure = event.code === 4001 ||
351
244
  event.reason?.includes('Unauthorized') ||
352
245
  (event.code === 1006 && !everConnected)
@@ -375,29 +268,21 @@ export class PlatformConnection {
375
268
  case 'paired':
376
269
  this.isConnected = true
377
270
  this.connectionId = message.connectionId as string
378
- // Connection status printed by onConnected callback
379
- // Start heartbeat to keep server-side TTL refreshed
380
271
  this.startHeartbeat()
381
272
  this.callbacks.onConnected?.(message.connectionId as string)
382
273
  break
383
-
384
274
  case 'web_connected':
385
275
  this.callbacks.onWebConnected?.()
386
276
  trackEvent(AnalyticsEvents.WEB_CLIENT_CONNECTED)
387
277
  break
388
-
389
278
  case 'web_disconnected':
390
279
  this.callbacks.onWebDisconnected?.()
391
280
  trackEvent(AnalyticsEvents.WEB_CLIENT_DISCONNECTED)
392
281
  break
393
-
394
282
  case 'pong':
395
283
  this.missedPongs = 0
396
284
  break
397
-
398
285
  default:
399
- // Relay message from web to wsHandler
400
- // These are messages like 'execute', 'initTab', 'autocomplete', etc.
401
286
  this.callbacks.onRelayedMessage?.(message)
402
287
  break
403
288
  }
@@ -420,29 +305,18 @@ export class PlatformConnection {
420
305
  }, delay)
421
306
  }
422
307
 
423
- /**
424
- * Send message to platform (will be relayed to web if connected)
425
- */
426
308
  send(message: unknown): void {
427
309
  if (this.ws && this.ws.readyState === WebSocketImpl.OPEN) {
428
310
  this.ws.send(JSON.stringify(message))
429
311
  }
430
312
  }
431
313
 
432
- /**
433
- * Check if connected to platform
434
- */
435
314
  isConnectedToPlatform(): boolean {
436
315
  return this.isConnected && this.ws?.readyState === WebSocketImpl.OPEN
437
316
  }
438
317
 
439
- /**
440
- * Disconnect from platform
441
- */
442
318
  disconnect(): void {
443
319
  this.isIntentionallyClosed = true
444
-
445
- // Stop heartbeat and token refresh checks
446
320
  this.stopHeartbeat()
447
321
  this.stopTokenRefreshCheck()
448
322