mstro-app 0.5.0 → 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 (556) hide show
  1. package/LICENSE +129 -190
  2. package/PRIVACY.md +3 -3
  3. package/README.md +5 -1
  4. package/bin/commands/config.js +0 -1
  5. package/bin/mstro.js +0 -1
  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 +0 -1
  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 +0 -1
  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 +0 -1
  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 +0 -1
  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.map +1 -1
  62. package/dist/server/cli/improvisation-history-store.js +0 -1
  63. package/dist/server/cli/improvisation-history-store.js.map +1 -1
  64. package/dist/server/cli/improvisation-movements.d.ts.map +1 -1
  65. package/dist/server/cli/improvisation-movements.js +0 -1
  66. package/dist/server/cli/improvisation-movements.js.map +1 -1
  67. package/dist/server/cli/improvisation-output-queue.d.ts.map +1 -1
  68. package/dist/server/cli/improvisation-output-queue.js +0 -1
  69. package/dist/server/cli/improvisation-output-queue.js.map +1 -1
  70. package/dist/server/cli/improvisation-retry.d.ts.map +1 -1
  71. package/dist/server/cli/improvisation-retry.js +0 -1
  72. package/dist/server/cli/improvisation-retry.js.map +1 -1
  73. package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
  74. package/dist/server/cli/improvisation-session-manager.js +0 -1
  75. package/dist/server/cli/improvisation-session-manager.js.map +1 -1
  76. package/dist/server/cli/improvisation-types.d.ts.map +1 -1
  77. package/dist/server/cli/improvisation-types.js +0 -1
  78. package/dist/server/cli/improvisation-types.js.map +1 -1
  79. package/dist/server/cli/retry/retry-best-result.d.ts.map +1 -1
  80. package/dist/server/cli/retry/retry-best-result.js +0 -1
  81. package/dist/server/cli/retry/retry-best-result.js.map +1 -1
  82. package/dist/server/cli/retry/retry-context-loss.d.ts.map +1 -1
  83. package/dist/server/cli/retry/retry-context-loss.js +0 -1
  84. package/dist/server/cli/retry/retry-context-loss.js.map +1 -1
  85. package/dist/server/cli/retry/retry-premature-completion.d.ts.map +1 -1
  86. package/dist/server/cli/retry/retry-premature-completion.js +1 -2
  87. package/dist/server/cli/retry/retry-premature-completion.js.map +1 -1
  88. package/dist/server/cli/retry/retry-recovery-strategies.d.ts.map +1 -1
  89. package/dist/server/cli/retry/retry-recovery-strategies.js +0 -1
  90. package/dist/server/cli/retry/retry-recovery-strategies.js.map +1 -1
  91. package/dist/server/cli/retry/retry-resume-strategy.d.ts.map +1 -1
  92. package/dist/server/cli/retry/retry-resume-strategy.js +0 -1
  93. package/dist/server/cli/retry/retry-resume-strategy.js.map +1 -1
  94. package/dist/server/cli/retry/retry-runner-factory.d.ts.map +1 -1
  95. package/dist/server/cli/retry/retry-runner-factory.js +0 -1
  96. package/dist/server/cli/retry/retry-runner-factory.js.map +1 -1
  97. package/dist/server/cli/retry/retry-tool-results.d.ts.map +1 -1
  98. package/dist/server/cli/retry/retry-tool-results.js +0 -1
  99. package/dist/server/cli/retry/retry-tool-results.js.map +1 -1
  100. package/dist/server/cli/retry/retry-types.d.ts.map +1 -1
  101. package/dist/server/cli/retry/retry-types.js +0 -1
  102. package/dist/server/cli/retry/retry-types.js.map +1 -1
  103. package/dist/server/index.js +0 -1
  104. package/dist/server/index.js.map +1 -1
  105. package/dist/server/mcp/bouncer-cli.js +0 -1
  106. package/dist/server/mcp/bouncer-cli.js.map +1 -1
  107. package/dist/server/mcp/bouncer-haiku.d.ts.map +1 -1
  108. package/dist/server/mcp/bouncer-haiku.js +0 -1
  109. package/dist/server/mcp/bouncer-haiku.js.map +1 -1
  110. package/dist/server/mcp/bouncer-integration.d.ts.map +1 -1
  111. package/dist/server/mcp/bouncer-integration.js +0 -1
  112. package/dist/server/mcp/bouncer-integration.js.map +1 -1
  113. package/dist/server/mcp/security-analysis.d.ts.map +1 -1
  114. package/dist/server/mcp/security-analysis.js +0 -1
  115. package/dist/server/mcp/security-analysis.js.map +1 -1
  116. package/dist/server/mcp/security-audit.d.ts.map +1 -1
  117. package/dist/server/mcp/security-audit.js +0 -1
  118. package/dist/server/mcp/security-audit.js.map +1 -1
  119. package/dist/server/mcp/security-patterns.d.ts.map +1 -1
  120. package/dist/server/mcp/security-patterns.js +0 -1
  121. package/dist/server/mcp/security-patterns.js.map +1 -1
  122. package/dist/server/mcp/server.js +0 -1
  123. package/dist/server/mcp/server.js.map +1 -1
  124. package/dist/server/routes/files.d.ts.map +1 -1
  125. package/dist/server/routes/files.js +0 -1
  126. package/dist/server/routes/files.js.map +1 -1
  127. package/dist/server/routes/improvise.d.ts.map +1 -1
  128. package/dist/server/routes/improvise.js +0 -1
  129. package/dist/server/routes/improvise.js.map +1 -1
  130. package/dist/server/routes/index.d.ts.map +1 -1
  131. package/dist/server/routes/index.js +0 -1
  132. package/dist/server/routes/index.js.map +1 -1
  133. package/dist/server/routes/instances.d.ts.map +1 -1
  134. package/dist/server/routes/instances.js +0 -1
  135. package/dist/server/routes/instances.js.map +1 -1
  136. package/dist/server/routes/notifications.d.ts.map +1 -1
  137. package/dist/server/routes/notifications.js +0 -1
  138. package/dist/server/routes/notifications.js.map +1 -1
  139. package/dist/server/server-setup.d.ts.map +1 -1
  140. package/dist/server/server-setup.js +0 -1
  141. package/dist/server/server-setup.js.map +1 -1
  142. package/dist/server/services/analytics.d.ts.map +1 -1
  143. package/dist/server/services/analytics.js +0 -1
  144. package/dist/server/services/analytics.js.map +1 -1
  145. package/dist/server/services/auth.d.ts.map +1 -1
  146. package/dist/server/services/auth.js +0 -1
  147. package/dist/server/services/auth.js.map +1 -1
  148. package/dist/server/services/client-id.d.ts.map +1 -1
  149. package/dist/server/services/client-id.js +0 -1
  150. package/dist/server/services/client-id.js.map +1 -1
  151. package/dist/server/services/file-explorer-ops.d.ts.map +1 -1
  152. package/dist/server/services/file-explorer-ops.js +0 -1
  153. package/dist/server/services/file-explorer-ops.js.map +1 -1
  154. package/dist/server/services/files.d.ts.map +1 -1
  155. package/dist/server/services/files.js +0 -1
  156. package/dist/server/services/files.js.map +1 -1
  157. package/dist/server/services/instances.d.ts.map +1 -1
  158. package/dist/server/services/instances.js +0 -1
  159. package/dist/server/services/instances.js.map +1 -1
  160. package/dist/server/services/pathUtils.d.ts.map +1 -1
  161. package/dist/server/services/pathUtils.js +0 -1
  162. package/dist/server/services/pathUtils.js.map +1 -1
  163. package/dist/server/services/plan/agent-loader.d.ts.map +1 -1
  164. package/dist/server/services/plan/agent-loader.js +0 -1
  165. package/dist/server/services/plan/agent-loader.js.map +1 -1
  166. package/dist/server/services/plan/board-config.d.ts.map +1 -1
  167. package/dist/server/services/plan/board-config.js +0 -1
  168. package/dist/server/services/plan/board-config.js.map +1 -1
  169. package/dist/server/services/plan/composer.d.ts.map +1 -1
  170. package/dist/server/services/plan/composer.js +0 -1
  171. package/dist/server/services/plan/composer.js.map +1 -1
  172. package/dist/server/services/plan/config-installer.d.ts.map +1 -1
  173. package/dist/server/services/plan/config-installer.js +0 -1
  174. package/dist/server/services/plan/config-installer.js.map +1 -1
  175. package/dist/server/services/plan/dependency-resolver.d.ts.map +1 -1
  176. package/dist/server/services/plan/dependency-resolver.js +0 -1
  177. package/dist/server/services/plan/dependency-resolver.js.map +1 -1
  178. package/dist/server/services/plan/executor.d.ts.map +1 -1
  179. package/dist/server/services/plan/executor.js +45 -3
  180. package/dist/server/services/plan/executor.js.map +1 -1
  181. package/dist/server/services/plan/front-matter.d.ts.map +1 -1
  182. package/dist/server/services/plan/front-matter.js +0 -1
  183. package/dist/server/services/plan/front-matter.js.map +1 -1
  184. package/dist/server/services/plan/issue-classification.d.ts.map +1 -1
  185. package/dist/server/services/plan/issue-classification.js +0 -1
  186. package/dist/server/services/plan/issue-classification.js.map +1 -1
  187. package/dist/server/services/plan/issue-loader.d.ts.map +1 -1
  188. package/dist/server/services/plan/issue-loader.js +0 -1
  189. package/dist/server/services/plan/issue-loader.js.map +1 -1
  190. package/dist/server/services/plan/issue-prompt-builder.d.ts.map +1 -1
  191. package/dist/server/services/plan/issue-prompt-builder.js +0 -1
  192. package/dist/server/services/plan/issue-prompt-builder.js.map +1 -1
  193. package/dist/server/services/plan/issue-retry.d.ts +3 -1
  194. package/dist/server/services/plan/issue-retry.d.ts.map +1 -1
  195. package/dist/server/services/plan/issue-retry.js +2 -1
  196. package/dist/server/services/plan/issue-retry.js.map +1 -1
  197. package/dist/server/services/plan/issue-writer.d.ts.map +1 -1
  198. package/dist/server/services/plan/issue-writer.js +0 -1
  199. package/dist/server/services/plan/issue-writer.js.map +1 -1
  200. package/dist/server/services/plan/output-manager.d.ts.map +1 -1
  201. package/dist/server/services/plan/output-manager.js +0 -1
  202. package/dist/server/services/plan/output-manager.js.map +1 -1
  203. package/dist/server/services/plan/parser-core.d.ts.map +1 -1
  204. package/dist/server/services/plan/parser-core.js +0 -1
  205. package/dist/server/services/plan/parser-core.js.map +1 -1
  206. package/dist/server/services/plan/parser-migration.d.ts.map +1 -1
  207. package/dist/server/services/plan/parser-migration.js +0 -1
  208. package/dist/server/services/plan/parser-migration.js.map +1 -1
  209. package/dist/server/services/plan/parser.d.ts.map +1 -1
  210. package/dist/server/services/plan/parser.js +0 -1
  211. package/dist/server/services/plan/parser.js.map +1 -1
  212. package/dist/server/services/plan/progress-log.d.ts.map +1 -1
  213. package/dist/server/services/plan/progress-log.js +0 -1
  214. package/dist/server/services/plan/progress-log.js.map +1 -1
  215. package/dist/server/services/plan/prompt-builder.d.ts.map +1 -1
  216. package/dist/server/services/plan/prompt-builder.js +0 -1
  217. package/dist/server/services/plan/prompt-builder.js.map +1 -1
  218. package/dist/server/services/plan/readiness-planner.d.ts.map +1 -1
  219. package/dist/server/services/plan/readiness-planner.js +0 -1
  220. package/dist/server/services/plan/readiness-planner.js.map +1 -1
  221. package/dist/server/services/plan/review-gate.d.ts.map +1 -1
  222. package/dist/server/services/plan/review-gate.js +0 -1
  223. package/dist/server/services/plan/review-gate.js.map +1 -1
  224. package/dist/server/services/plan/state-reconciler.d.ts.map +1 -1
  225. package/dist/server/services/plan/state-reconciler.js +0 -1
  226. package/dist/server/services/plan/state-reconciler.js.map +1 -1
  227. package/dist/server/services/plan/types.d.ts.map +1 -1
  228. package/dist/server/services/plan/types.js +0 -1
  229. package/dist/server/services/plan/types.js.map +1 -1
  230. package/dist/server/services/plan/watcher.d.ts.map +1 -1
  231. package/dist/server/services/plan/watcher.js +0 -1
  232. package/dist/server/services/plan/watcher.js.map +1 -1
  233. package/dist/server/services/platform-credentials.d.ts.map +1 -1
  234. package/dist/server/services/platform-credentials.js +0 -1
  235. package/dist/server/services/platform-credentials.js.map +1 -1
  236. package/dist/server/services/platform-token-lifecycle.d.ts +70 -0
  237. package/dist/server/services/platform-token-lifecycle.d.ts.map +1 -0
  238. package/dist/server/services/platform-token-lifecycle.js +156 -0
  239. package/dist/server/services/platform-token-lifecycle.js.map +1 -0
  240. package/dist/server/services/platform.d.ts +21 -56
  241. package/dist/server/services/platform.d.ts.map +1 -1
  242. package/dist/server/services/platform.js +98 -142
  243. package/dist/server/services/platform.js.map +1 -1
  244. package/dist/server/services/sentry.d.ts.map +1 -1
  245. package/dist/server/services/sentry.js +0 -1
  246. package/dist/server/services/sentry.js.map +1 -1
  247. package/dist/server/services/settings.d.ts.map +1 -1
  248. package/dist/server/services/settings.js +0 -1
  249. package/dist/server/services/settings.js.map +1 -1
  250. package/dist/server/services/terminal/pty-manager.d.ts.map +1 -1
  251. package/dist/server/services/terminal/pty-manager.js +0 -1
  252. package/dist/server/services/terminal/pty-manager.js.map +1 -1
  253. package/dist/server/services/terminal/pty-utils.d.ts.map +1 -1
  254. package/dist/server/services/terminal/pty-utils.js +0 -1
  255. package/dist/server/services/terminal/pty-utils.js.map +1 -1
  256. package/dist/server/services/websocket/autocomplete.d.ts.map +1 -1
  257. package/dist/server/services/websocket/autocomplete.js +0 -1
  258. package/dist/server/services/websocket/autocomplete.js.map +1 -1
  259. package/dist/server/services/websocket/file-definition-handlers.d.ts.map +1 -1
  260. package/dist/server/services/websocket/file-definition-handlers.js +0 -1
  261. package/dist/server/services/websocket/file-definition-handlers.js.map +1 -1
  262. package/dist/server/services/websocket/file-download-handler.d.ts.map +1 -1
  263. package/dist/server/services/websocket/file-download-handler.js +0 -1
  264. package/dist/server/services/websocket/file-download-handler.js.map +1 -1
  265. package/dist/server/services/websocket/file-explorer-handlers.d.ts.map +1 -1
  266. package/dist/server/services/websocket/file-explorer-handlers.js +0 -1
  267. package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -1
  268. package/dist/server/services/websocket/file-search-handlers.d.ts.map +1 -1
  269. package/dist/server/services/websocket/file-search-handlers.js +0 -1
  270. package/dist/server/services/websocket/file-search-handlers.js.map +1 -1
  271. package/dist/server/services/websocket/file-upload-handler.d.ts +2 -3
  272. package/dist/server/services/websocket/file-upload-handler.d.ts.map +1 -1
  273. package/dist/server/services/websocket/file-upload-handler.js +4 -7
  274. package/dist/server/services/websocket/file-upload-handler.js.map +1 -1
  275. package/dist/server/services/websocket/file-utils.d.ts.map +1 -1
  276. package/dist/server/services/websocket/file-utils.js +0 -1
  277. package/dist/server/services/websocket/file-utils.js.map +1 -1
  278. package/dist/server/services/websocket/git-branch-handlers.d.ts.map +1 -1
  279. package/dist/server/services/websocket/git-branch-handlers.js +0 -1
  280. package/dist/server/services/websocket/git-branch-handlers.js.map +1 -1
  281. package/dist/server/services/websocket/git-diff-handlers.d.ts.map +1 -1
  282. package/dist/server/services/websocket/git-diff-handlers.js +0 -1
  283. package/dist/server/services/websocket/git-diff-handlers.js.map +1 -1
  284. package/dist/server/services/websocket/git-handlers.d.ts.map +1 -1
  285. package/dist/server/services/websocket/git-handlers.js +58 -6
  286. package/dist/server/services/websocket/git-handlers.js.map +1 -1
  287. package/dist/server/services/websocket/git-head-watcher.d.ts.map +1 -1
  288. package/dist/server/services/websocket/git-head-watcher.js +0 -1
  289. package/dist/server/services/websocket/git-head-watcher.js.map +1 -1
  290. package/dist/server/services/websocket/git-log-handlers.d.ts.map +1 -1
  291. package/dist/server/services/websocket/git-log-handlers.js +0 -1
  292. package/dist/server/services/websocket/git-log-handlers.js.map +1 -1
  293. package/dist/server/services/websocket/git-pr-handlers.d.ts.map +1 -1
  294. package/dist/server/services/websocket/git-pr-handlers.js +0 -1
  295. package/dist/server/services/websocket/git-pr-handlers.js.map +1 -1
  296. package/dist/server/services/websocket/git-tag-handlers.d.ts.map +1 -1
  297. package/dist/server/services/websocket/git-tag-handlers.js +0 -1
  298. package/dist/server/services/websocket/git-tag-handlers.js.map +1 -1
  299. package/dist/server/services/websocket/git-utils.d.ts +18 -3
  300. package/dist/server/services/websocket/git-utils.d.ts.map +1 -1
  301. package/dist/server/services/websocket/git-utils.js +58 -8
  302. package/dist/server/services/websocket/git-utils.js.map +1 -1
  303. package/dist/server/services/websocket/git-worktree-handlers.d.ts.map +1 -1
  304. package/dist/server/services/websocket/git-worktree-handlers.js +230 -14
  305. package/dist/server/services/websocket/git-worktree-handlers.js.map +1 -1
  306. package/dist/server/services/websocket/handler-context.d.ts.map +1 -1
  307. package/dist/server/services/websocket/handler-context.js +0 -1
  308. package/dist/server/services/websocket/handler-context.js.map +1 -1
  309. package/dist/server/services/websocket/handler.d.ts.map +1 -1
  310. package/dist/server/services/websocket/handler.js +3 -4
  311. package/dist/server/services/websocket/handler.js.map +1 -1
  312. package/dist/server/services/websocket/index.d.ts.map +1 -1
  313. package/dist/server/services/websocket/index.js +0 -1
  314. package/dist/server/services/websocket/index.js.map +1 -1
  315. package/dist/server/services/websocket/msg-id-tracker.d.ts.map +1 -1
  316. package/dist/server/services/websocket/msg-id-tracker.js +0 -1
  317. package/dist/server/services/websocket/msg-id-tracker.js.map +1 -1
  318. package/dist/server/services/websocket/plan-board-handlers.d.ts.map +1 -1
  319. package/dist/server/services/websocket/plan-board-handlers.js +0 -1
  320. package/dist/server/services/websocket/plan-board-handlers.js.map +1 -1
  321. package/dist/server/services/websocket/plan-execution-handlers.d.ts.map +1 -1
  322. package/dist/server/services/websocket/plan-execution-handlers.js +6 -2
  323. package/dist/server/services/websocket/plan-execution-handlers.js.map +1 -1
  324. package/dist/server/services/websocket/plan-handlers.d.ts.map +1 -1
  325. package/dist/server/services/websocket/plan-handlers.js +0 -1
  326. package/dist/server/services/websocket/plan-handlers.js.map +1 -1
  327. package/dist/server/services/websocket/plan-helpers.d.ts.map +1 -1
  328. package/dist/server/services/websocket/plan-helpers.js +0 -1
  329. package/dist/server/services/websocket/plan-helpers.js.map +1 -1
  330. package/dist/server/services/websocket/plan-issue-handlers.d.ts.map +1 -1
  331. package/dist/server/services/websocket/plan-issue-handlers.js +0 -1
  332. package/dist/server/services/websocket/plan-issue-handlers.js.map +1 -1
  333. package/dist/server/services/websocket/plan-sprint-handlers.d.ts.map +1 -1
  334. package/dist/server/services/websocket/plan-sprint-handlers.js +0 -1
  335. package/dist/server/services/websocket/plan-sprint-handlers.js.map +1 -1
  336. package/dist/server/services/websocket/quality-complexity.d.ts.map +1 -1
  337. package/dist/server/services/websocket/quality-complexity.js +0 -1
  338. package/dist/server/services/websocket/quality-complexity.js.map +1 -1
  339. package/dist/server/services/websocket/quality-grading.d.ts +46 -0
  340. package/dist/server/services/websocket/quality-grading.d.ts.map +1 -0
  341. package/dist/server/services/websocket/quality-grading.js +482 -0
  342. package/dist/server/services/websocket/quality-grading.js.map +1 -0
  343. package/dist/server/services/websocket/quality-handlers.d.ts.map +1 -1
  344. package/dist/server/services/websocket/quality-handlers.js +0 -1
  345. package/dist/server/services/websocket/quality-handlers.js.map +1 -1
  346. package/dist/server/services/websocket/quality-linting.d.ts.map +1 -1
  347. package/dist/server/services/websocket/quality-linting.js +0 -1
  348. package/dist/server/services/websocket/quality-linting.js.map +1 -1
  349. package/dist/server/services/websocket/quality-persistence.d.ts +14 -0
  350. package/dist/server/services/websocket/quality-persistence.d.ts.map +1 -1
  351. package/dist/server/services/websocket/quality-persistence.js +28 -12
  352. package/dist/server/services/websocket/quality-persistence.js.map +1 -1
  353. package/dist/server/services/websocket/quality-review-agent.d.ts.map +1 -1
  354. package/dist/server/services/websocket/quality-review-agent.js +0 -1
  355. package/dist/server/services/websocket/quality-review-agent.js.map +1 -1
  356. package/dist/server/services/websocket/quality-service.d.ts +3 -1
  357. package/dist/server/services/websocket/quality-service.d.ts.map +1 -1
  358. package/dist/server/services/websocket/quality-service.js +53 -58
  359. package/dist/server/services/websocket/quality-service.js.map +1 -1
  360. package/dist/server/services/websocket/quality-tools.d.ts +1 -1
  361. package/dist/server/services/websocket/quality-tools.d.ts.map +1 -1
  362. package/dist/server/services/websocket/quality-tools.js +6 -3
  363. package/dist/server/services/websocket/quality-tools.js.map +1 -1
  364. package/dist/server/services/websocket/quality-types.d.ts +18 -2
  365. package/dist/server/services/websocket/quality-types.d.ts.map +1 -1
  366. package/dist/server/services/websocket/quality-types.js +0 -1
  367. package/dist/server/services/websocket/quality-types.js.map +1 -1
  368. package/dist/server/services/websocket/session-handlers.d.ts.map +1 -1
  369. package/dist/server/services/websocket/session-handlers.js +0 -1
  370. package/dist/server/services/websocket/session-handlers.js.map +1 -1
  371. package/dist/server/services/websocket/session-history.d.ts.map +1 -1
  372. package/dist/server/services/websocket/session-history.js +0 -1
  373. package/dist/server/services/websocket/session-history.js.map +1 -1
  374. package/dist/server/services/websocket/session-initialization.d.ts.map +1 -1
  375. package/dist/server/services/websocket/session-initialization.js +0 -1
  376. package/dist/server/services/websocket/session-initialization.js.map +1 -1
  377. package/dist/server/services/websocket/session-registry.d.ts.map +1 -1
  378. package/dist/server/services/websocket/session-registry.js +0 -1
  379. package/dist/server/services/websocket/session-registry.js.map +1 -1
  380. package/dist/server/services/websocket/settings-handlers.d.ts.map +1 -1
  381. package/dist/server/services/websocket/settings-handlers.js +0 -1
  382. package/dist/server/services/websocket/settings-handlers.js.map +1 -1
  383. package/dist/server/services/websocket/skill-handlers.d.ts.map +1 -1
  384. package/dist/server/services/websocket/skill-handlers.js +0 -1
  385. package/dist/server/services/websocket/skill-handlers.js.map +1 -1
  386. package/dist/server/services/websocket/skill-watcher.d.ts.map +1 -1
  387. package/dist/server/services/websocket/skill-watcher.js +0 -1
  388. package/dist/server/services/websocket/skill-watcher.js.map +1 -1
  389. package/dist/server/services/websocket/tab-broadcast.d.ts.map +1 -1
  390. package/dist/server/services/websocket/tab-broadcast.js +0 -1
  391. package/dist/server/services/websocket/tab-broadcast.js.map +1 -1
  392. package/dist/server/services/websocket/tab-event-buffer.d.ts.map +1 -1
  393. package/dist/server/services/websocket/tab-event-buffer.js +0 -1
  394. package/dist/server/services/websocket/tab-event-buffer.js.map +1 -1
  395. package/dist/server/services/websocket/tab-event-replay.d.ts.map +1 -1
  396. package/dist/server/services/websocket/tab-event-replay.js +0 -1
  397. package/dist/server/services/websocket/tab-event-replay.js.map +1 -1
  398. package/dist/server/services/websocket/tab-handlers.d.ts.map +1 -1
  399. package/dist/server/services/websocket/tab-handlers.js +0 -1
  400. package/dist/server/services/websocket/tab-handlers.js.map +1 -1
  401. package/dist/server/services/websocket/terminal-handlers.d.ts.map +1 -1
  402. package/dist/server/services/websocket/terminal-handlers.js +39 -4
  403. package/dist/server/services/websocket/terminal-handlers.js.map +1 -1
  404. package/dist/server/services/websocket/types.d.ts +2 -2
  405. package/dist/server/services/websocket/types.d.ts.map +1 -1
  406. package/dist/server/services/websocket/types.js +2 -3
  407. package/dist/server/services/websocket/types.js.map +1 -1
  408. package/dist/server/utils/agent-manager.d.ts.map +1 -1
  409. package/dist/server/utils/agent-manager.js +0 -1
  410. package/dist/server/utils/agent-manager.js.map +1 -1
  411. package/dist/server/utils/paths.d.ts.map +1 -1
  412. package/dist/server/utils/paths.js +0 -1
  413. package/dist/server/utils/paths.js.map +1 -1
  414. package/dist/server/utils/port-manager.d.ts.map +1 -1
  415. package/dist/server/utils/port-manager.js +0 -1
  416. package/dist/server/utils/port-manager.js.map +1 -1
  417. package/dist/server/utils/port.d.ts.map +1 -1
  418. package/dist/server/utils/port.js +0 -1
  419. package/dist/server/utils/port.js.map +1 -1
  420. package/package.json +2 -2
  421. package/server/cli/headless/claude-invoker-process.ts +0 -1
  422. package/server/cli/headless/claude-invoker-stall.ts +0 -1
  423. package/server/cli/headless/claude-invoker-stream.ts +0 -1
  424. package/server/cli/headless/claude-invoker-tools.ts +0 -1
  425. package/server/cli/headless/claude-invoker.ts +0 -1
  426. package/server/cli/headless/haiku-assessments.ts +0 -1
  427. package/server/cli/headless/headless-logger.ts +0 -1
  428. package/server/cli/headless/index.ts +0 -1
  429. package/server/cli/headless/native-timeout-detector.ts +0 -1
  430. package/server/cli/headless/output-utils.ts +0 -1
  431. package/server/cli/headless/prompt-utils.ts +0 -1
  432. package/server/cli/headless/resilient-runner.ts +0 -1
  433. package/server/cli/headless/retry-strategies.ts +0 -1
  434. package/server/cli/headless/runner.ts +0 -1
  435. package/server/cli/headless/stall-assessor.ts +0 -1
  436. package/server/cli/headless/tool-watchdog.ts +0 -1
  437. package/server/cli/headless/types.ts +0 -1
  438. package/server/cli/improvisation-attachments.ts +0 -1
  439. package/server/cli/improvisation-history-store.ts +0 -1
  440. package/server/cli/improvisation-movements.ts +0 -1
  441. package/server/cli/improvisation-output-queue.ts +0 -1
  442. package/server/cli/improvisation-retry.ts +0 -1
  443. package/server/cli/improvisation-session-manager.ts +0 -1
  444. package/server/cli/improvisation-types.ts +0 -1
  445. package/server/cli/retry/retry-best-result.ts +0 -1
  446. package/server/cli/retry/retry-context-loss.ts +0 -1
  447. package/server/cli/retry/retry-premature-completion.ts +1 -2
  448. package/server/cli/retry/retry-recovery-strategies.ts +0 -1
  449. package/server/cli/retry/retry-resume-strategy.ts +0 -1
  450. package/server/cli/retry/retry-runner-factory.ts +0 -1
  451. package/server/cli/retry/retry-tool-results.ts +0 -1
  452. package/server/cli/retry/retry-types.ts +0 -1
  453. package/server/index.ts +0 -1
  454. package/server/mcp/bouncer-cli.ts +0 -1
  455. package/server/mcp/bouncer-haiku.ts +0 -1
  456. package/server/mcp/bouncer-integration.ts +0 -1
  457. package/server/mcp/security-analysis.ts +0 -1
  458. package/server/mcp/security-audit.ts +0 -1
  459. package/server/mcp/security-patterns.ts +0 -1
  460. package/server/mcp/server.ts +0 -1
  461. package/server/routes/files.ts +0 -1
  462. package/server/routes/improvise.ts +0 -1
  463. package/server/routes/index.ts +0 -1
  464. package/server/routes/instances.ts +0 -1
  465. package/server/routes/notifications.ts +0 -1
  466. package/server/server-setup.ts +0 -1
  467. package/server/services/analytics.ts +0 -1
  468. package/server/services/auth.ts +0 -1
  469. package/server/services/client-id.ts +0 -1
  470. package/server/services/file-explorer-ops.ts +0 -1
  471. package/server/services/files.ts +0 -1
  472. package/server/services/instances.ts +0 -1
  473. package/server/services/pathUtils.ts +0 -1
  474. package/server/services/plan/agent-loader.ts +0 -1
  475. package/server/services/plan/agents/code-review.md +13 -11
  476. package/server/services/plan/board-config.ts +0 -1
  477. package/server/services/plan/composer.ts +0 -1
  478. package/server/services/plan/config-installer.ts +0 -1
  479. package/server/services/plan/dependency-resolver.ts +0 -1
  480. package/server/services/plan/executor.ts +45 -3
  481. package/server/services/plan/front-matter.ts +0 -1
  482. package/server/services/plan/issue-classification.ts +0 -1
  483. package/server/services/plan/issue-loader.ts +0 -1
  484. package/server/services/plan/issue-prompt-builder.ts +0 -1
  485. package/server/services/plan/issue-retry.ts +5 -2
  486. package/server/services/plan/issue-writer.ts +0 -1
  487. package/server/services/plan/output-manager.ts +0 -1
  488. package/server/services/plan/parser-core.ts +0 -1
  489. package/server/services/plan/parser-migration.ts +0 -1
  490. package/server/services/plan/parser.ts +0 -1
  491. package/server/services/plan/progress-log.ts +0 -1
  492. package/server/services/plan/prompt-builder.ts +0 -1
  493. package/server/services/plan/readiness-planner.ts +0 -1
  494. package/server/services/plan/review-gate.ts +0 -1
  495. package/server/services/plan/state-reconciler.ts +0 -1
  496. package/server/services/plan/types.ts +0 -1
  497. package/server/services/plan/watcher.ts +0 -1
  498. package/server/services/platform-credentials.ts +0 -1
  499. package/server/services/platform-token-lifecycle.ts +171 -0
  500. package/server/services/platform.ts +106 -148
  501. package/server/services/sentry.ts +0 -1
  502. package/server/services/settings.ts +0 -1
  503. package/server/services/terminal/pty-manager.ts +0 -1
  504. package/server/services/terminal/pty-utils.ts +0 -1
  505. package/server/services/websocket/autocomplete.ts +0 -1
  506. package/server/services/websocket/file-definition-handlers.ts +0 -1
  507. package/server/services/websocket/file-download-handler.ts +0 -1
  508. package/server/services/websocket/file-explorer-handlers.ts +0 -1
  509. package/server/services/websocket/file-search-handlers.ts +0 -1
  510. package/server/services/websocket/file-upload-handler.ts +6 -5
  511. package/server/services/websocket/file-utils.ts +0 -1
  512. package/server/services/websocket/git-branch-handlers.ts +0 -1
  513. package/server/services/websocket/git-diff-handlers.ts +0 -1
  514. package/server/services/websocket/git-handlers.ts +66 -10
  515. package/server/services/websocket/git-head-watcher.ts +0 -1
  516. package/server/services/websocket/git-log-handlers.ts +0 -1
  517. package/server/services/websocket/git-pr-handlers.ts +0 -1
  518. package/server/services/websocket/git-tag-handlers.ts +0 -1
  519. package/server/services/websocket/git-utils.ts +69 -9
  520. package/server/services/websocket/git-worktree-handlers.ts +260 -17
  521. package/server/services/websocket/handler-context.ts +0 -1
  522. package/server/services/websocket/handler.ts +3 -4
  523. package/server/services/websocket/index.ts +0 -1
  524. package/server/services/websocket/msg-id-tracker.ts +0 -1
  525. package/server/services/websocket/plan-board-handlers.ts +0 -1
  526. package/server/services/websocket/plan-execution-handlers.ts +6 -2
  527. package/server/services/websocket/plan-handlers.ts +0 -1
  528. package/server/services/websocket/plan-helpers.ts +0 -1
  529. package/server/services/websocket/plan-issue-handlers.ts +0 -1
  530. package/server/services/websocket/plan-sprint-handlers.ts +0 -1
  531. package/server/services/websocket/quality-complexity.ts +0 -1
  532. package/server/services/websocket/quality-grading.ts +611 -0
  533. package/server/services/websocket/quality-handlers.ts +0 -1
  534. package/server/services/websocket/quality-linting.ts +0 -1
  535. package/server/services/websocket/quality-persistence.ts +30 -8
  536. package/server/services/websocket/quality-review-agent.ts +0 -1
  537. package/server/services/websocket/quality-service.ts +54 -55
  538. package/server/services/websocket/quality-tools.ts +11 -3
  539. package/server/services/websocket/quality-types.ts +21 -3
  540. package/server/services/websocket/session-handlers.ts +0 -1
  541. package/server/services/websocket/session-history.ts +0 -1
  542. package/server/services/websocket/session-initialization.ts +0 -1
  543. package/server/services/websocket/session-registry.ts +0 -1
  544. package/server/services/websocket/settings-handlers.ts +0 -1
  545. package/server/services/websocket/skill-handlers.ts +0 -1
  546. package/server/services/websocket/skill-watcher.ts +0 -1
  547. package/server/services/websocket/tab-broadcast.ts +0 -1
  548. package/server/services/websocket/tab-event-buffer.ts +0 -1
  549. package/server/services/websocket/tab-event-replay.ts +0 -1
  550. package/server/services/websocket/tab-handlers.ts +0 -1
  551. package/server/services/websocket/terminal-handlers.ts +39 -3
  552. package/server/services/websocket/types.ts +2 -3
  553. package/server/utils/agent-manager.ts +0 -1
  554. package/server/utils/paths.ts +0 -1
  555. package/server/utils/port-manager.ts +0 -1
  556. package/server/utils/port.ts +0 -1
@@ -0,0 +1,171 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+
3
+ /**
4
+ * Token Lifecycle — refresh, verify, and auth-expired signaling for the
5
+ * platform device token. Extracted from PlatformConnection so the relay
6
+ * lifecycle (sockets, reconnect, heartbeat) and the auth lifecycle (token
7
+ * refresh, verify, expired-signal) can be reasoned about apart. The token
8
+ * lifecycle has its own clock (24h periodic check), its own remote endpoints
9
+ * (/refresh, /verify), and its own failure modes (revocation vs. transient
10
+ * network error) — none of which need to be in PlatformConnection.
11
+ */
12
+
13
+ import {
14
+ getCredentials,
15
+ shouldRefreshToken,
16
+ updateCredentials,
17
+ } from './platform-credentials.js'
18
+
19
+ const PERIODIC_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000
20
+
21
+ export interface TokenLifecycleDeps {
22
+ /** Platform base URL — used to compose /api/auth/device/{refresh,verify} */
23
+ platformUrl: string
24
+ /** Send a message upstream over the live relay socket (no-op if closed). */
25
+ send: (message: unknown) => void
26
+ /** Read the current relay connection ID at the moment auth-expired fires. */
27
+ getConnectionId: () => string | null
28
+ }
29
+
30
+ export class TokenLifecycle {
31
+ private intervalHandle: ReturnType<typeof setInterval> | null = null
32
+
33
+ constructor(private readonly deps: TokenLifecycleDeps) {}
34
+
35
+ /**
36
+ * Refresh the device token if it's older than the refresh interval.
37
+ * Returns `true` if the token is (still) valid after this call, `false`
38
+ * if refresh was attempted and rejected with an auth error — in which
39
+ * case the caller should surface an auth-expired signal to the web
40
+ * rather than silently reusing a dead token.
41
+ */
42
+ async maybeRefresh(): Promise<boolean> {
43
+ const creds = getCredentials()
44
+ if (!creds) return false
45
+ if (!shouldRefreshToken(creds)) return true
46
+
47
+ try {
48
+ const response = await fetch(`${this.deps.platformUrl}/api/auth/device/refresh`, {
49
+ method: 'POST',
50
+ headers: {
51
+ 'Authorization': `Bearer ${creds.token}`,
52
+ 'Content-Type': 'application/json'
53
+ }
54
+ })
55
+
56
+ if (response.ok) {
57
+ const data = await response.json() as { accessToken: string }
58
+ updateCredentials({
59
+ token: data.accessToken,
60
+ lastRefreshedAt: new Date().toISOString()
61
+ })
62
+ return true
63
+ }
64
+ if (response.status === 401 || response.status === 403) {
65
+ console.warn(`[Platform] Token refresh failed — auth is expired (${response.status}). Run \`mstro login --force\`.`)
66
+ this.notifyAuthExpired()
67
+ return false
68
+ }
69
+ console.warn(`[Platform] Token refresh failed with status ${response.status}, will retry later`)
70
+ return true
71
+ } catch (err) {
72
+ console.warn('[Platform] Token refresh error:', err)
73
+ return true
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Verify the current token against the platform. A rejection (401/403)
79
+ * means the token is permanently invalid (revoked, signing-key rotation,
80
+ * account deleted); the caller should stop looping reconnects and tell
81
+ * the user to run `mstro login --force`.
82
+ *
83
+ * Returns `true` when the token is valid or the verification endpoint
84
+ * is unreachable (we prefer false negatives to false positives — a
85
+ * network blip shouldn't force a re-login).
86
+ */
87
+ async verify(): Promise<boolean> {
88
+ const creds = getCredentials()
89
+ if (!creds?.token) return false
90
+ try {
91
+ const response = await fetch(`${this.deps.platformUrl}/api/auth/device/verify`, {
92
+ method: 'POST',
93
+ headers: { 'Authorization': `Bearer ${creds.token}` },
94
+ })
95
+ if (response.status === 401 || response.status === 403) {
96
+ console.warn(`[Platform] Token verify rejected (${response.status}) — auth is expired.`)
97
+ return false
98
+ }
99
+ return true
100
+ } catch {
101
+ // Network error: treat as "probably valid" so a flaky connection
102
+ // doesn't force users to re-login. The WebSocket open itself will
103
+ // catch a truly bad token via the 4001 path.
104
+ return true
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Surface an auth-expired condition to any paired web clients.
110
+ *
111
+ * Two cooperating paths deliver this signal — either alone is enough,
112
+ * both together cover every timing edge:
113
+ *
114
+ * 1. **CLI-initiated (this method):** we detected a 401 from the
115
+ * `/refresh` or `/verify` endpoint *while the relay socket is
116
+ * still open*. The injected `send` pushes the message upstream so
117
+ * the server relays it to paired webs before the CLI closes.
118
+ * A no-op if the socket is already closed.
119
+ *
120
+ * 2. **Server-initiated:** when the platform closes a CLI socket
121
+ * with 4001 or 4008, `handleAuthClose` in `clientHandlers.ts`
122
+ * broadcasts the same `clientAuthExpired` to paired webs. This
123
+ * covers cases where the CLI never had a chance to detect the
124
+ * rejection itself (e.g. token revoked while the socket was idle,
125
+ * server-side token rotation).
126
+ *
127
+ * IMPORTANT: never route this through PlatformConnection's
128
+ * `onRelayedMessage` callback — that callback feeds INCOMING web→CLI
129
+ * requests into the local handler, which would treat
130
+ * `clientAuthExpired` as an unknown inbound request.
131
+ */
132
+ notifyAuthExpired(): void {
133
+ this.deps.send({
134
+ type: 'clientAuthExpired',
135
+ data: {
136
+ connectionId: this.deps.getConnectionId(),
137
+ message: 'The CLI\'s device token is invalid — run `mstro login --force` on the machine.',
138
+ },
139
+ })
140
+ }
141
+
142
+ /**
143
+ * Best-effort token verification, fired in parallel with the socket
144
+ * open so a slow verify endpoint never delays reconnect.
145
+ *
146
+ * Only runs when the token is stale enough that we'd be about to
147
+ * refresh anyway — keeps the hot path free of an extra network call.
148
+ * A truly-revoked token that slips past this check still hits 4001
149
+ * on the WebSocket, which also triggers `notifyAuthExpired`.
150
+ */
151
+ maybeVerifyInParallel(): void {
152
+ const creds = getCredentials()
153
+ if (!creds || !shouldRefreshToken(creds)) return
154
+ this.verify().then((valid) => {
155
+ if (!valid) this.notifyAuthExpired()
156
+ }).catch(() => { /* network error — rely on 4001 close path */ })
157
+ }
158
+
159
+ startPeriodicCheck(): void {
160
+ this.intervalHandle = setInterval(() => {
161
+ this.maybeRefresh()
162
+ }, PERIODIC_CHECK_INTERVAL_MS)
163
+ }
164
+
165
+ stopPeriodicCheck(): void {
166
+ if (this.intervalHandle) {
167
+ clearInterval(this.intervalHandle)
168
+ this.intervalHandle = null
169
+ }
170
+ }
171
+ }
@@ -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
  * Platform Connection Service
@@ -14,12 +13,8 @@ import { arch, hostname, type } from 'node:os'
14
13
  import { basename } from 'node:path'
15
14
  import { AnalyticsEvents, trackEvent } from './analytics.js'
16
15
  import { getClientId } from './client-id.js'
17
- import {
18
- CLI_VERSION,
19
- getCredentials,
20
- shouldRefreshToken,
21
- updateCredentials,
22
- } from './platform-credentials.js'
16
+ import { CLI_VERSION, getCredentials } from './platform-credentials.js'
17
+ import { TokenLifecycle } from './platform-token-lifecycle.js'
23
18
  import { captureException } from './sentry.js'
24
19
 
25
20
  /**
@@ -50,6 +45,27 @@ if (typeof WebSocket !== 'undefined') {
50
45
  // PLATFORM_URL is set via --server / --dev flag in mstro.js
51
46
  const DEFAULT_PLATFORM_URL = process.env.PLATFORM_URL || 'https://api.mstro.app'
52
47
 
48
+ /**
49
+ * Relay wire-format version this CLI speaks. Bumped by the server when the
50
+ * relay protocol changes incompatibly. Must match (or exceed) the server's
51
+ * `minProtocolVersion` in `server/src/relay/version-policy.ts` — when the
52
+ * server's floor moves above this value, the upgrade handshake returns 426
53
+ * and the CLI surfaces the upgrade message via `handleSocketClose`.
54
+ *
55
+ * This is a build-time constant, not user-configurable: a stale CLI must be
56
+ * told to upgrade rather than allowed to opt itself into compatibility.
57
+ */
58
+ const PROTOCOL_VERSION = 1
59
+
60
+ /**
61
+ * Long sentinel delay used after a 426 protocol-too-old close. The CLI
62
+ * auto-upgrades on the next `mstro` invocation, so a tight reconnect loop
63
+ * would just hammer the server with rejections that policy already decided
64
+ * to refuse. One hour is long enough to count as "stop", short enough that
65
+ * a forgotten foreground process eventually retries on its own.
66
+ */
67
+ const PROTOCOL_UPGRADE_RECONNECT_DELAY_MS = 60 * 60 * 1000
68
+
53
69
  interface ConnectionCallbacks {
54
70
  onConnected?: (connectionId: string) => void
55
71
  onDisconnected?: () => void
@@ -73,11 +89,12 @@ export class PlatformConnection {
73
89
  private callbacks: ConnectionCallbacks
74
90
  private connectionId: string | null = null
75
91
  private isConnected = false
76
- private tokenRefreshInterval: ReturnType<typeof setInterval> | null = null
77
92
  private heartbeatInterval: ReturnType<typeof setInterval> | null = null
78
93
  private missedPongs = 0
79
94
  private everConnected = false
95
+ private protocolUpgradeRequired = false
80
96
  private readonly startedAt: string
97
+ private readonly tokens: TokenLifecycle
81
98
 
82
99
  constructor(
83
100
  workingDirectory: string,
@@ -88,120 +105,13 @@ export class PlatformConnection {
88
105
  this.platformUrl = platformUrl || DEFAULT_PLATFORM_URL
89
106
  this.callbacks = callbacks
90
107
  this.startedAt = new Date().toISOString()
91
- }
92
-
93
- /**
94
- * Refresh the device token if it's older than the refresh interval.
95
- * Returns `true` if the token is (still) valid after this call, `false`
96
- * if refresh was attempted and rejected with an auth error — in which
97
- * case the caller should surface an auth-expired signal to the web
98
- * rather than silently reusing a dead token.
99
- */
100
- private async maybeRefreshToken(): Promise<boolean> {
101
- const creds = getCredentials()
102
- if (!creds) return false
103
- if (!shouldRefreshToken(creds)) return true
104
-
105
- try {
106
- const response = await fetch(`${this.platformUrl}/api/auth/device/refresh`, {
107
- method: 'POST',
108
- headers: {
109
- 'Authorization': `Bearer ${creds.token}`,
110
- 'Content-Type': 'application/json'
111
- }
112
- })
113
-
114
- if (response.ok) {
115
- const data = await response.json() as { accessToken: string }
116
- updateCredentials({
117
- token: data.accessToken,
118
- lastRefreshedAt: new Date().toISOString()
119
- })
120
- return true
121
- }
122
- if (response.status === 401 || response.status === 403) {
123
- console.warn(`[Platform] Token refresh failed — auth is expired (${response.status}). Run \`mstro login --force\`.`)
124
- this.notifyAuthExpired()
125
- return false
126
- }
127
- console.warn(`[Platform] Token refresh failed with status ${response.status}, will retry later`)
128
- return true
129
- } catch (err) {
130
- console.warn('[Platform] Token refresh error:', err)
131
- return true
132
- }
133
- }
134
-
135
- /**
136
- * Verify the current token against the platform. A rejection (401/403)
137
- * means the token is permanently invalid (revoked, signing-key rotation,
138
- * account deleted); the caller should stop looping reconnects and tell
139
- * the user to run `mstro login --force`.
140
- *
141
- * Returns `true` when the token is valid or the verification endpoint
142
- * is unreachable (we prefer false negatives to false positives — a
143
- * network blip shouldn't force a re-login).
144
- */
145
- private async verifyToken(): Promise<boolean> {
146
- const creds = getCredentials()
147
- if (!creds?.token) return false
148
- try {
149
- const response = await fetch(`${this.platformUrl}/api/auth/device/verify`, {
150
- method: 'POST',
151
- headers: { 'Authorization': `Bearer ${creds.token}` },
152
- })
153
- if (response.status === 401 || response.status === 403) {
154
- console.warn(`[Platform] Token verify rejected (${response.status}) — auth is expired.`)
155
- return false
156
- }
157
- return true
158
- } catch {
159
- // Network error: treat as "probably valid" so a flaky connection
160
- // doesn't force users to re-login. The WebSocket open itself will
161
- // catch a truly bad token via the 4001 path.
162
- return true
163
- }
164
- }
165
-
166
- /**
167
- * Surface an auth-expired condition to any paired web clients.
168
- *
169
- * Two cooperating paths deliver this signal — either alone is enough,
170
- * both together cover every timing edge:
171
- *
172
- * 1. **CLI-initiated (this method):** we detected a 401 from the
173
- * `/refresh` or `/verify` endpoint *while the relay socket is
174
- * still open*. `this.send` pushes the message upstream so the
175
- * server relays it to paired webs before we intentionally close.
176
- * A no-op if the socket is already closed.
177
- *
178
- * 2. **Server-initiated:** when the platform closes a CLI socket
179
- * with 4001 or 4008, `handleAuthClose` in `clientHandlers.ts`
180
- * broadcasts the same `clientAuthExpired` to paired webs. This
181
- * covers the cases where the CLI never had a chance to detect
182
- * the rejection itself (e.g. token revoked while the socket was
183
- * idle, server-side token rotation).
184
- *
185
- * IMPORTANT: never call `this.callbacks.onRelayedMessage` here —
186
- * that callback feeds INCOMING web→CLI requests into the local handler,
187
- * which would treat `clientAuthExpired` as an unknown inbound request.
188
- */
189
- private notifyAuthExpired(): void {
190
- this.send({
191
- type: 'clientAuthExpired',
192
- data: {
193
- connectionId: this.connectionId,
194
- message: 'The CLI\'s device token is invalid — run `mstro login --force` on the machine.',
195
- },
108
+ this.tokens = new TokenLifecycle({
109
+ platformUrl: this.platformUrl,
110
+ send: (msg) => this.send(msg),
111
+ getConnectionId: () => this.connectionId,
196
112
  })
197
113
  }
198
114
 
199
- private startTokenRefreshCheck(): void {
200
- this.tokenRefreshInterval = setInterval(() => {
201
- this.maybeRefreshToken()
202
- }, 24 * 60 * 60 * 1000)
203
- }
204
-
205
115
  private startHeartbeat(): void {
206
116
  this.missedPongs = 0
207
117
  this.heartbeatInterval = setInterval(() => this.heartbeatTick(), 25_000)
@@ -232,15 +142,9 @@ export class PlatformConnection {
232
142
  }
233
143
  }
234
144
 
235
- private stopTokenRefreshCheck(): void {
236
- if (this.tokenRefreshInterval) {
237
- clearInterval(this.tokenRefreshInterval)
238
- this.tokenRefreshInterval = null
239
- }
240
- }
241
-
242
145
  connect(): void {
243
146
  this.isIntentionallyClosed = false
147
+ this.protocolUpgradeRequired = false
244
148
 
245
149
  const authToken = getCredentials()?.token
246
150
  if (!authToken) {
@@ -262,24 +166,7 @@ export class PlatformConnection {
262
166
 
263
167
  const connectionTimeout = this.startConnectionTimeout()
264
168
  this.attachSocketHandlers(this.ws, authToken, connectionTimeout)
265
- this.maybeVerifyTokenInParallel()
266
- }
267
-
268
- /**
269
- * Best-effort token verification, fired in parallel with the socket
270
- * open so a slow verify endpoint never delays reconnect.
271
- *
272
- * Only runs when the token is stale enough that we'd be about to
273
- * refresh anyway — keeps the hot path free of an extra network call.
274
- * A truly-revoked token that slips past this check still hits 4001
275
- * on the WebSocket, which also triggers `notifyAuthExpired`.
276
- */
277
- private maybeVerifyTokenInParallel(): void {
278
- const creds = getCredentials()
279
- if (!creds || !shouldRefreshToken(creds)) return
280
- this.verifyToken().then((valid) => {
281
- if (!valid) this.notifyAuthExpired()
282
- }).catch(() => { /* network error — rely on 4001 close path */ })
169
+ this.tokens.maybeVerifyInParallel()
283
170
  }
284
171
 
285
172
  private buildConnectionUrl(): string {
@@ -295,6 +182,7 @@ export class PlatformConnection {
295
182
  cliVersion: CLI_VERSION,
296
183
  capabilities: JSON.stringify({}),
297
184
  startedAt: this.startedAt,
185
+ protocolVersion: String(PROTOCOL_VERSION),
298
186
  })
299
187
  return `${this.platformUrl.replace(/^http/, 'ws')}/ws/client?${params}`
300
188
  }
@@ -319,8 +207,8 @@ export class PlatformConnection {
319
207
  ws.onopen = () => {
320
208
  clearTimeout(connectionTimeout)
321
209
  ws.send(JSON.stringify({ type: 'auth', token: authToken }))
322
- this.maybeRefreshToken()
323
- this.startTokenRefreshCheck()
210
+ this.tokens.maybeRefresh()
211
+ this.tokens.startPeriodicCheck()
324
212
  this.reconnectAttempts = 0
325
213
  trackEvent(AnalyticsEvents.PLATFORM_CONNECTED)
326
214
  }
@@ -342,6 +230,24 @@ export class PlatformConnection {
342
230
  clearTimeout(connectionTimeout)
343
231
  // onclose will be called after this
344
232
  }
233
+
234
+ // The Node `ws` library exposes the raw HTTP upgrade response as an
235
+ // `unexpected-response` event when the server returns a non-101 status
236
+ // (for us: 426 Upgrade Required from the protocol-version gate). The
237
+ // global WebSocket in Bun / Node 21+ doesn't expose this — for those
238
+ // runtimes we rely on the close-code path below. Both paths feed into
239
+ // `protocolUpgradeRequired`, so `handleSocketClose` can decide once.
240
+ const wsWithEmitter = ws as unknown as {
241
+ on?: (event: string, listener: (...args: unknown[]) => void) => void
242
+ }
243
+ if (typeof wsWithEmitter.on === 'function') {
244
+ wsWithEmitter.on('unexpected-response', (...args: unknown[]) => {
245
+ const response = args[1] as { statusCode?: number } | undefined
246
+ if (response?.statusCode === 426) {
247
+ this.protocolUpgradeRequired = true
248
+ }
249
+ })
250
+ }
345
251
  }
346
252
 
347
253
  private handleSocketClose(event: CloseEvent): void {
@@ -350,6 +256,11 @@ export class PlatformConnection {
350
256
 
351
257
  if (this.isIntentionallyClosed) return
352
258
 
259
+ if (this.isProtocolTooOldClose(event)) {
260
+ this.handleProtocolUpgradeRequired()
261
+ return
262
+ }
263
+
353
264
  const isAuthFailure = event.code === 4001 ||
354
265
  event.reason?.includes('Unauthorized') ||
355
266
  (event.code === 1006 && !this.everConnected)
@@ -357,7 +268,7 @@ export class PlatformConnection {
357
268
  if (isAuthFailure) {
358
269
  console.error('\n❌ Authentication failed. Your device token may be invalid or expired.')
359
270
  console.error(' Run `mstro login --force` to re-authenticate.\n')
360
- this.notifyAuthExpired()
271
+ this.tokens.notifyAuthExpired()
361
272
  this.callbacks.onError?.('Authentication failed - run `mstro login --force`')
362
273
  return
363
274
  }
@@ -368,6 +279,53 @@ export class PlatformConnection {
368
279
  this.scheduleReconnect()
369
280
  }
370
281
 
282
+ /**
283
+ * The relay can refuse a CLI for being too old in two shapes:
284
+ *
285
+ * 1. **HTTP 426 during upgrade** — the `ws` library surfaces this via
286
+ * its `unexpected-response` event, which sets
287
+ * `protocolUpgradeRequired` before `onclose` fires. This is the path
288
+ * the current server takes (`checkProtocolVersionGate`).
289
+ *
290
+ * 2. **WS close 1002/1008 with `protocol-too-old` reason** — reserved
291
+ * for a future server variant that completes the upgrade and then
292
+ * closes (e.g. when the policy check moves into a post-handshake
293
+ * stage). The reason string is part of the contract with the server.
294
+ *
295
+ * Anything else (1006 race after a successful run, 1001 going-away on
296
+ * deploy) must fall through to the regular reconnect path so transient
297
+ * failures keep healing on their own.
298
+ */
299
+ private isProtocolTooOldClose(event: CloseEvent): boolean {
300
+ if (this.protocolUpgradeRequired) return true
301
+ const code = event.code
302
+ if ((code === 1002 || code === 1008) && event.reason?.includes('protocol-too-old')) {
303
+ return true
304
+ }
305
+ return false
306
+ }
307
+
308
+ private handleProtocolUpgradeRequired(): void {
309
+ const message = 'Mstro CLI is out of date for this orchestra. Run `mstro` again to upgrade and reconnect.'
310
+ console.error(`\n❌ ${message}\n`)
311
+ this.callbacks.onError?.(message)
312
+ this.callbacks.onDisconnected?.()
313
+
314
+ // Don't exit the process — terminal sessions and other local state stay
315
+ // alive while the user re-runs `mstro`. Schedule a single, far-future
316
+ // reconnect as a sentinel so we silently retry exactly once if the
317
+ // process is somehow still around an hour later. The existing
318
+ // exponential-backoff path is bypassed deliberately: hammering a server
319
+ // that has already decided to refuse on policy is pointless.
320
+ if (this.reconnectTimeout) {
321
+ clearTimeout(this.reconnectTimeout)
322
+ }
323
+ this.reconnectTimeout = setTimeout(() => {
324
+ this.reconnectTimeout = null
325
+ this.connect()
326
+ }, PROTOCOL_UPGRADE_RECONNECT_DELAY_MS)
327
+ }
328
+
371
329
  private handleMessage(message: Record<string, unknown>): void {
372
330
  switch (message.type) {
373
331
  case 'paired':
@@ -430,7 +388,7 @@ export class PlatformConnection {
430
388
  disconnect(): void {
431
389
  this.isIntentionallyClosed = true
432
390
  this.stopHeartbeat()
433
- this.stopTokenRefreshCheck()
391
+ this.tokens.stopPeriodicCheck()
434
392
 
435
393
  if (this.reconnectTimeout) {
436
394
  clearTimeout(this.reconnectTimeout)
@@ -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 { existsSync, readFileSync } from 'node:fs'
5
4
  import { homedir } from 'node:os'
@@ -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
  * Settings Service
@@ -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
  * PTY Manager - Manages pseudo-terminal sessions for shell access.
@@ -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
  * PTY Utilities — node-pty loading, shell detection, scrollback buffer, and types.
@@ -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
  * Autocomplete Service
@@ -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 { spawn } from 'node:child_process';
5
4
  import { join, relative } from 'node:path';
@@ -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
  * Chunked File Download Handler
@@ -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 {
5
4
  createDirectory,
@@ -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 { spawn } from 'node:child_process';
5
4
  import { relative } from 'node:path';
@@ -1,12 +1,13 @@
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
  * Chunked File Upload Handler
6
5
  *
7
6
  * Receives files in chunks over WebSocket from remote web clients.
7
+ * The destination working directory is passed per-call (effective dir for the tab,
8
+ * which resolves to the worktree path when the tab is on a worktree).
8
9
  * - When `targetPath` is provided: streams to <workingDir>/<targetPath> (drag-drop into file tree).
9
- * - Otherwise: streams to .mstro/tmp/attachments/{tabId}/ (prompt attachments).
10
+ * - Otherwise: streams to <workingDir>/.mstro/tmp/attachments/{tabId}/ (prompt attachments).
10
11
  */
11
12
 
12
13
  import type { WriteStream } from 'node:fs';
@@ -50,7 +51,6 @@ export class FileUploadHandler {
50
51
  private cleanupInterval: ReturnType<typeof setInterval>;
51
52
 
52
53
  constructor(
53
- private workingDir: string,
54
54
  private ctx?: HandlerContext,
55
55
  ) {
56
56
  // Periodically clean up stale uploads
@@ -74,6 +74,7 @@ export class FileUploadHandler {
74
74
  send: (ws: WSContext, response: WebSocketResponse) => void,
75
75
  tabId: string,
76
76
  data: { uploadId: string; fileName: string; fileSize: number; mimeType: string; isImage: boolean; totalChunks: number; targetPath?: string; overwrite?: boolean },
77
+ workingDir: string,
77
78
  permission?: 'view',
78
79
  ): void {
79
80
  const { uploadId, fileName, fileSize, mimeType, isImage, totalChunks, targetPath, overwrite } = data;
@@ -89,8 +90,8 @@ export class FileUploadHandler {
89
90
  }
90
91
 
91
92
  const resolved = targetPath !== undefined
92
- ? resolveFileTreeTarget({ targetPath, fileName, workingDir: this.workingDir, permission, overwrite })
93
- : resolveAttachmentTarget({ workingDir: this.workingDir, tabId, fileName });
93
+ ? resolveFileTreeTarget({ targetPath, fileName, workingDir, permission, overwrite })
94
+ : resolveAttachmentTarget({ workingDir, tabId, fileName });
94
95
 
95
96
  if (!resolved.ok) {
96
97
  sendError(resolved.error);
@@ -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
  * File Utilities
@@ -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 { executeGitCommand, sendGitError } from './git-utils.js';
5
4
  import { findWorktreePathForBranch, handleTabWorktreeSwitch } from './git-worktree-handlers.js';
@@ -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 { readFileSync } from 'node:fs';
5
4
  import { join } from 'node:path';