mstro-app 0.4.52 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (590) hide show
  1. package/LICENSE +129 -190
  2. package/PRIVACY.md +3 -3
  3. package/README.md +15 -6
  4. package/bin/commands/config.js +0 -1
  5. package/bin/mstro.js +1 -2
  6. package/bin/postinstall.js +0 -1
  7. package/dist/server/cli/headless/claude-invoker-process.d.ts.map +1 -1
  8. package/dist/server/cli/headless/claude-invoker-process.js +0 -1
  9. package/dist/server/cli/headless/claude-invoker-process.js.map +1 -1
  10. package/dist/server/cli/headless/claude-invoker-stall.d.ts.map +1 -1
  11. package/dist/server/cli/headless/claude-invoker-stall.js +7 -3
  12. package/dist/server/cli/headless/claude-invoker-stall.js.map +1 -1
  13. package/dist/server/cli/headless/claude-invoker-stream.d.ts.map +1 -1
  14. package/dist/server/cli/headless/claude-invoker-stream.js +0 -1
  15. package/dist/server/cli/headless/claude-invoker-stream.js.map +1 -1
  16. package/dist/server/cli/headless/claude-invoker-tools.d.ts.map +1 -1
  17. package/dist/server/cli/headless/claude-invoker-tools.js +0 -1
  18. package/dist/server/cli/headless/claude-invoker-tools.js.map +1 -1
  19. package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -1
  20. package/dist/server/cli/headless/claude-invoker.js +1 -2
  21. package/dist/server/cli/headless/claude-invoker.js.map +1 -1
  22. package/dist/server/cli/headless/haiku-assessments.d.ts.map +1 -1
  23. package/dist/server/cli/headless/haiku-assessments.js +0 -1
  24. package/dist/server/cli/headless/haiku-assessments.js.map +1 -1
  25. package/dist/server/cli/headless/headless-logger.d.ts.map +1 -1
  26. package/dist/server/cli/headless/headless-logger.js +0 -1
  27. package/dist/server/cli/headless/headless-logger.js.map +1 -1
  28. package/dist/server/cli/headless/index.d.ts.map +1 -1
  29. package/dist/server/cli/headless/index.js +0 -1
  30. package/dist/server/cli/headless/index.js.map +1 -1
  31. package/dist/server/cli/headless/native-timeout-detector.d.ts.map +1 -1
  32. package/dist/server/cli/headless/native-timeout-detector.js +0 -1
  33. package/dist/server/cli/headless/native-timeout-detector.js.map +1 -1
  34. package/dist/server/cli/headless/output-utils.d.ts.map +1 -1
  35. package/dist/server/cli/headless/output-utils.js +0 -1
  36. package/dist/server/cli/headless/output-utils.js.map +1 -1
  37. package/dist/server/cli/headless/prompt-utils.d.ts.map +1 -1
  38. package/dist/server/cli/headless/prompt-utils.js +0 -1
  39. package/dist/server/cli/headless/prompt-utils.js.map +1 -1
  40. package/dist/server/cli/headless/resilient-runner.d.ts.map +1 -1
  41. package/dist/server/cli/headless/resilient-runner.js +0 -1
  42. package/dist/server/cli/headless/resilient-runner.js.map +1 -1
  43. package/dist/server/cli/headless/retry-strategies.d.ts.map +1 -1
  44. package/dist/server/cli/headless/retry-strategies.js +0 -1
  45. package/dist/server/cli/headless/retry-strategies.js.map +1 -1
  46. package/dist/server/cli/headless/runner.d.ts.map +1 -1
  47. package/dist/server/cli/headless/runner.js +63 -68
  48. package/dist/server/cli/headless/runner.js.map +1 -1
  49. package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
  50. package/dist/server/cli/headless/stall-assessor.js +9 -5
  51. package/dist/server/cli/headless/stall-assessor.js.map +1 -1
  52. package/dist/server/cli/headless/tool-watchdog.d.ts.map +1 -1
  53. package/dist/server/cli/headless/tool-watchdog.js +0 -1
  54. package/dist/server/cli/headless/tool-watchdog.js.map +1 -1
  55. package/dist/server/cli/headless/types.d.ts.map +1 -1
  56. package/dist/server/cli/headless/types.js +0 -1
  57. package/dist/server/cli/headless/types.js.map +1 -1
  58. package/dist/server/cli/improvisation-attachments.d.ts.map +1 -1
  59. package/dist/server/cli/improvisation-attachments.js +0 -1
  60. package/dist/server/cli/improvisation-attachments.js.map +1 -1
  61. package/dist/server/cli/improvisation-history-store.d.ts +16 -0
  62. package/dist/server/cli/improvisation-history-store.d.ts.map +1 -0
  63. package/dist/server/cli/improvisation-history-store.js +51 -0
  64. package/dist/server/cli/improvisation-history-store.js.map +1 -0
  65. package/dist/server/cli/improvisation-movements.d.ts +31 -0
  66. package/dist/server/cli/improvisation-movements.d.ts.map +1 -0
  67. package/dist/server/cli/improvisation-movements.js +92 -0
  68. package/dist/server/cli/improvisation-movements.js.map +1 -0
  69. package/dist/server/cli/improvisation-output-queue.d.ts +13 -0
  70. package/dist/server/cli/improvisation-output-queue.d.ts.map +1 -0
  71. package/dist/server/cli/improvisation-output-queue.js +39 -0
  72. package/dist/server/cli/improvisation-output-queue.js.map +1 -0
  73. package/dist/server/cli/improvisation-retry.d.ts +21 -51
  74. package/dist/server/cli/improvisation-retry.d.ts.map +1 -1
  75. package/dist/server/cli/improvisation-retry.js +18 -434
  76. package/dist/server/cli/improvisation-retry.js.map +1 -1
  77. package/dist/server/cli/improvisation-session-manager.d.ts +10 -8
  78. package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
  79. package/dist/server/cli/improvisation-session-manager.js +53 -149
  80. package/dist/server/cli/improvisation-session-manager.js.map +1 -1
  81. package/dist/server/cli/improvisation-types.d.ts.map +1 -1
  82. package/dist/server/cli/improvisation-types.js +0 -1
  83. package/dist/server/cli/improvisation-types.js.map +1 -1
  84. package/dist/server/cli/retry/retry-best-result.d.ts +4 -0
  85. package/dist/server/cli/retry/retry-best-result.d.ts.map +1 -0
  86. package/dist/server/cli/retry/retry-best-result.js +60 -0
  87. package/dist/server/cli/retry/retry-best-result.js.map +1 -0
  88. package/dist/server/cli/retry/retry-context-loss.d.ts +6 -0
  89. package/dist/server/cli/retry/retry-context-loss.d.ts.map +1 -0
  90. package/dist/server/cli/retry/retry-context-loss.js +67 -0
  91. package/dist/server/cli/retry/retry-context-loss.js.map +1 -0
  92. package/dist/server/cli/retry/retry-premature-completion.d.ts +5 -0
  93. package/dist/server/cli/retry/retry-premature-completion.d.ts.map +1 -0
  94. package/dist/server/cli/retry/retry-premature-completion.js +80 -0
  95. package/dist/server/cli/retry/retry-premature-completion.js.map +1 -0
  96. package/dist/server/cli/retry/retry-recovery-strategies.d.ts +13 -0
  97. package/dist/server/cli/retry/retry-recovery-strategies.d.ts.map +1 -0
  98. package/dist/server/cli/retry/retry-recovery-strategies.js +165 -0
  99. package/dist/server/cli/retry/retry-recovery-strategies.js.map +1 -0
  100. package/dist/server/cli/retry/retry-resume-strategy.d.ts +12 -0
  101. package/dist/server/cli/retry/retry-resume-strategy.d.ts.map +1 -0
  102. package/dist/server/cli/retry/retry-resume-strategy.js +21 -0
  103. package/dist/server/cli/retry/retry-resume-strategy.js.map +1 -0
  104. package/dist/server/cli/retry/retry-runner-factory.d.ts +11 -0
  105. package/dist/server/cli/retry/retry-runner-factory.d.ts.map +1 -0
  106. package/dist/server/cli/retry/retry-runner-factory.js +59 -0
  107. package/dist/server/cli/retry/retry-runner-factory.js.map +1 -0
  108. package/dist/server/cli/retry/retry-tool-results.d.ts +9 -0
  109. package/dist/server/cli/retry/retry-tool-results.d.ts.map +1 -0
  110. package/dist/server/cli/retry/retry-tool-results.js +23 -0
  111. package/dist/server/cli/retry/retry-tool-results.js.map +1 -0
  112. package/dist/server/cli/retry/retry-types.d.ts +30 -0
  113. package/dist/server/cli/retry/retry-types.d.ts.map +1 -0
  114. package/dist/server/cli/retry/retry-types.js +3 -0
  115. package/dist/server/cli/retry/retry-types.js.map +1 -0
  116. package/dist/server/index.js +21 -110
  117. package/dist/server/index.js.map +1 -1
  118. package/dist/server/mcp/bouncer-cli.js +0 -1
  119. package/dist/server/mcp/bouncer-cli.js.map +1 -1
  120. package/dist/server/mcp/bouncer-haiku.d.ts.map +1 -1
  121. package/dist/server/mcp/bouncer-haiku.js +0 -1
  122. package/dist/server/mcp/bouncer-haiku.js.map +1 -1
  123. package/dist/server/mcp/bouncer-integration.d.ts.map +1 -1
  124. package/dist/server/mcp/bouncer-integration.js +0 -1
  125. package/dist/server/mcp/bouncer-integration.js.map +1 -1
  126. package/dist/server/mcp/security-analysis.d.ts.map +1 -1
  127. package/dist/server/mcp/security-analysis.js +0 -1
  128. package/dist/server/mcp/security-analysis.js.map +1 -1
  129. package/dist/server/mcp/security-audit.d.ts.map +1 -1
  130. package/dist/server/mcp/security-audit.js +0 -1
  131. package/dist/server/mcp/security-audit.js.map +1 -1
  132. package/dist/server/mcp/security-patterns.d.ts.map +1 -1
  133. package/dist/server/mcp/security-patterns.js +0 -1
  134. package/dist/server/mcp/security-patterns.js.map +1 -1
  135. package/dist/server/mcp/server.js +0 -1
  136. package/dist/server/mcp/server.js.map +1 -1
  137. package/dist/server/routes/files.d.ts.map +1 -1
  138. package/dist/server/routes/files.js +0 -1
  139. package/dist/server/routes/files.js.map +1 -1
  140. package/dist/server/routes/improvise.d.ts.map +1 -1
  141. package/dist/server/routes/improvise.js +0 -1
  142. package/dist/server/routes/improvise.js.map +1 -1
  143. package/dist/server/routes/index.d.ts.map +1 -1
  144. package/dist/server/routes/index.js +0 -1
  145. package/dist/server/routes/index.js.map +1 -1
  146. package/dist/server/routes/instances.d.ts.map +1 -1
  147. package/dist/server/routes/instances.js +0 -1
  148. package/dist/server/routes/instances.js.map +1 -1
  149. package/dist/server/routes/notifications.d.ts.map +1 -1
  150. package/dist/server/routes/notifications.js +0 -1
  151. package/dist/server/routes/notifications.js.map +1 -1
  152. package/dist/server/server-setup.d.ts +16 -1
  153. package/dist/server/server-setup.d.ts.map +1 -1
  154. package/dist/server/server-setup.js +107 -1
  155. package/dist/server/server-setup.js.map +1 -1
  156. package/dist/server/services/analytics.d.ts.map +1 -1
  157. package/dist/server/services/analytics.js +0 -1
  158. package/dist/server/services/analytics.js.map +1 -1
  159. package/dist/server/services/auth.d.ts.map +1 -1
  160. package/dist/server/services/auth.js +0 -1
  161. package/dist/server/services/auth.js.map +1 -1
  162. package/dist/server/services/client-id.d.ts.map +1 -1
  163. package/dist/server/services/client-id.js +0 -1
  164. package/dist/server/services/client-id.js.map +1 -1
  165. package/dist/server/services/file-explorer-ops.d.ts.map +1 -1
  166. package/dist/server/services/file-explorer-ops.js +0 -1
  167. package/dist/server/services/file-explorer-ops.js.map +1 -1
  168. package/dist/server/services/files.d.ts.map +1 -1
  169. package/dist/server/services/files.js +0 -1
  170. package/dist/server/services/files.js.map +1 -1
  171. package/dist/server/services/instances.d.ts.map +1 -1
  172. package/dist/server/services/instances.js +0 -1
  173. package/dist/server/services/instances.js.map +1 -1
  174. package/dist/server/services/pathUtils.d.ts.map +1 -1
  175. package/dist/server/services/pathUtils.js +0 -1
  176. package/dist/server/services/pathUtils.js.map +1 -1
  177. package/dist/server/services/plan/agent-loader.d.ts.map +1 -1
  178. package/dist/server/services/plan/agent-loader.js +0 -1
  179. package/dist/server/services/plan/agent-loader.js.map +1 -1
  180. package/dist/server/services/plan/board-config.d.ts +21 -0
  181. package/dist/server/services/plan/board-config.d.ts.map +1 -0
  182. package/dist/server/services/plan/board-config.js +111 -0
  183. package/dist/server/services/plan/board-config.js.map +1 -0
  184. package/dist/server/services/plan/composer.d.ts +1 -1
  185. package/dist/server/services/plan/composer.d.ts.map +1 -1
  186. package/dist/server/services/plan/composer.js +7 -6
  187. package/dist/server/services/plan/composer.js.map +1 -1
  188. package/dist/server/services/plan/config-installer.d.ts.map +1 -1
  189. package/dist/server/services/plan/config-installer.js +0 -1
  190. package/dist/server/services/plan/config-installer.js.map +1 -1
  191. package/dist/server/services/plan/dependency-resolver.d.ts.map +1 -1
  192. package/dist/server/services/plan/dependency-resolver.js +0 -1
  193. package/dist/server/services/plan/dependency-resolver.js.map +1 -1
  194. package/dist/server/services/plan/executor.d.ts +48 -48
  195. package/dist/server/services/plan/executor.d.ts.map +1 -1
  196. package/dist/server/services/plan/executor.js +202 -458
  197. package/dist/server/services/plan/executor.js.map +1 -1
  198. package/dist/server/services/plan/front-matter.d.ts.map +1 -1
  199. package/dist/server/services/plan/front-matter.js +0 -1
  200. package/dist/server/services/plan/front-matter.js.map +1 -1
  201. package/dist/server/services/plan/issue-classification.d.ts.map +1 -1
  202. package/dist/server/services/plan/issue-classification.js +0 -1
  203. package/dist/server/services/plan/issue-classification.js.map +1 -1
  204. package/dist/server/services/plan/issue-loader.d.ts +16 -0
  205. package/dist/server/services/plan/issue-loader.d.ts.map +1 -0
  206. package/dist/server/services/plan/issue-loader.js +45 -0
  207. package/dist/server/services/plan/issue-loader.js.map +1 -0
  208. package/dist/server/services/plan/issue-prompt-builder.d.ts.map +1 -1
  209. package/dist/server/services/plan/issue-prompt-builder.js +0 -1
  210. package/dist/server/services/plan/issue-prompt-builder.js.map +1 -1
  211. package/dist/server/services/plan/issue-retry.d.ts +3 -1
  212. package/dist/server/services/plan/issue-retry.d.ts.map +1 -1
  213. package/dist/server/services/plan/issue-retry.js +2 -1
  214. package/dist/server/services/plan/issue-retry.js.map +1 -1
  215. package/dist/server/services/plan/issue-writer.d.ts +34 -0
  216. package/dist/server/services/plan/issue-writer.d.ts.map +1 -0
  217. package/dist/server/services/plan/issue-writer.js +109 -0
  218. package/dist/server/services/plan/issue-writer.js.map +1 -0
  219. package/dist/server/services/plan/output-manager.js +2 -2
  220. package/dist/server/services/plan/output-manager.js.map +1 -1
  221. package/dist/server/services/plan/parser-core.d.ts.map +1 -1
  222. package/dist/server/services/plan/parser-core.js +0 -1
  223. package/dist/server/services/plan/parser-core.js.map +1 -1
  224. package/dist/server/services/plan/parser-migration.d.ts.map +1 -1
  225. package/dist/server/services/plan/parser-migration.js +0 -1
  226. package/dist/server/services/plan/parser-migration.js.map +1 -1
  227. package/dist/server/services/plan/parser.d.ts.map +1 -1
  228. package/dist/server/services/plan/parser.js +0 -1
  229. package/dist/server/services/plan/parser.js.map +1 -1
  230. package/dist/server/services/plan/progress-log.d.ts +11 -0
  231. package/dist/server/services/plan/progress-log.d.ts.map +1 -0
  232. package/dist/server/services/plan/progress-log.js +80 -0
  233. package/dist/server/services/plan/progress-log.js.map +1 -0
  234. package/dist/server/services/plan/prompt-builder.d.ts.map +1 -1
  235. package/dist/server/services/plan/prompt-builder.js +48 -32
  236. package/dist/server/services/plan/prompt-builder.js.map +1 -1
  237. package/dist/server/services/plan/readiness-planner.d.ts +15 -0
  238. package/dist/server/services/plan/readiness-planner.d.ts.map +1 -0
  239. package/dist/server/services/plan/readiness-planner.js +40 -0
  240. package/dist/server/services/plan/readiness-planner.js.map +1 -0
  241. package/dist/server/services/plan/review-gate.d.ts +31 -0
  242. package/dist/server/services/plan/review-gate.d.ts.map +1 -1
  243. package/dist/server/services/plan/review-gate.js +52 -3
  244. package/dist/server/services/plan/review-gate.js.map +1 -1
  245. package/dist/server/services/plan/state-reconciler.d.ts.map +1 -1
  246. package/dist/server/services/plan/state-reconciler.js +0 -1
  247. package/dist/server/services/plan/state-reconciler.js.map +1 -1
  248. package/dist/server/services/plan/types.d.ts.map +1 -1
  249. package/dist/server/services/plan/types.js +0 -1
  250. package/dist/server/services/plan/types.js.map +1 -1
  251. package/dist/server/services/plan/watcher.d.ts.map +1 -1
  252. package/dist/server/services/plan/watcher.js +0 -1
  253. package/dist/server/services/plan/watcher.js.map +1 -1
  254. package/dist/server/services/platform-credentials.d.ts.map +1 -1
  255. package/dist/server/services/platform-credentials.js +0 -1
  256. package/dist/server/services/platform-credentials.js.map +1 -1
  257. package/dist/server/services/platform-token-lifecycle.d.ts +70 -0
  258. package/dist/server/services/platform-token-lifecycle.d.ts.map +1 -0
  259. package/dist/server/services/platform-token-lifecycle.js +156 -0
  260. package/dist/server/services/platform-token-lifecycle.js.map +1 -0
  261. package/dist/server/services/platform.d.ts +25 -4
  262. package/dist/server/services/platform.d.ts.map +1 -1
  263. package/dist/server/services/platform.js +150 -92
  264. package/dist/server/services/platform.js.map +1 -1
  265. package/dist/server/services/sentry.d.ts.map +1 -1
  266. package/dist/server/services/sentry.js +0 -1
  267. package/dist/server/services/sentry.js.map +1 -1
  268. package/dist/server/services/settings.d.ts.map +1 -1
  269. package/dist/server/services/settings.js +0 -1
  270. package/dist/server/services/settings.js.map +1 -1
  271. package/dist/server/services/terminal/pty-manager.d.ts.map +1 -1
  272. package/dist/server/services/terminal/pty-manager.js +0 -1
  273. package/dist/server/services/terminal/pty-manager.js.map +1 -1
  274. package/dist/server/services/terminal/pty-utils.d.ts.map +1 -1
  275. package/dist/server/services/terminal/pty-utils.js +0 -1
  276. package/dist/server/services/terminal/pty-utils.js.map +1 -1
  277. package/dist/server/services/websocket/autocomplete.d.ts.map +1 -1
  278. package/dist/server/services/websocket/autocomplete.js +0 -1
  279. package/dist/server/services/websocket/autocomplete.js.map +1 -1
  280. package/dist/server/services/websocket/file-definition-handlers.d.ts.map +1 -1
  281. package/dist/server/services/websocket/file-definition-handlers.js +0 -1
  282. package/dist/server/services/websocket/file-definition-handlers.js.map +1 -1
  283. package/dist/server/services/websocket/file-download-handler.d.ts +17 -0
  284. package/dist/server/services/websocket/file-download-handler.d.ts.map +1 -0
  285. package/dist/server/services/websocket/file-download-handler.js +164 -0
  286. package/dist/server/services/websocket/file-download-handler.js.map +1 -0
  287. package/dist/server/services/websocket/file-explorer-handlers.d.ts.map +1 -1
  288. package/dist/server/services/websocket/file-explorer-handlers.js +0 -1
  289. package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -1
  290. package/dist/server/services/websocket/file-search-handlers.d.ts.map +1 -1
  291. package/dist/server/services/websocket/file-search-handlers.js +0 -1
  292. package/dist/server/services/websocket/file-search-handlers.js.map +1 -1
  293. package/dist/server/services/websocket/file-upload-handler.d.ts +2 -3
  294. package/dist/server/services/websocket/file-upload-handler.d.ts.map +1 -1
  295. package/dist/server/services/websocket/file-upload-handler.js +4 -7
  296. package/dist/server/services/websocket/file-upload-handler.js.map +1 -1
  297. package/dist/server/services/websocket/file-utils.d.ts.map +1 -1
  298. package/dist/server/services/websocket/file-utils.js +0 -1
  299. package/dist/server/services/websocket/file-utils.js.map +1 -1
  300. package/dist/server/services/websocket/git-branch-handlers.d.ts.map +1 -1
  301. package/dist/server/services/websocket/git-branch-handlers.js +0 -1
  302. package/dist/server/services/websocket/git-branch-handlers.js.map +1 -1
  303. package/dist/server/services/websocket/git-diff-handlers.d.ts.map +1 -1
  304. package/dist/server/services/websocket/git-diff-handlers.js +0 -1
  305. package/dist/server/services/websocket/git-diff-handlers.js.map +1 -1
  306. package/dist/server/services/websocket/git-handlers.d.ts.map +1 -1
  307. package/dist/server/services/websocket/git-handlers.js +58 -6
  308. package/dist/server/services/websocket/git-handlers.js.map +1 -1
  309. package/dist/server/services/websocket/git-head-watcher.d.ts.map +1 -1
  310. package/dist/server/services/websocket/git-head-watcher.js +0 -1
  311. package/dist/server/services/websocket/git-head-watcher.js.map +1 -1
  312. package/dist/server/services/websocket/git-log-handlers.d.ts.map +1 -1
  313. package/dist/server/services/websocket/git-log-handlers.js +0 -1
  314. package/dist/server/services/websocket/git-log-handlers.js.map +1 -1
  315. package/dist/server/services/websocket/git-pr-handlers.d.ts.map +1 -1
  316. package/dist/server/services/websocket/git-pr-handlers.js +0 -1
  317. package/dist/server/services/websocket/git-pr-handlers.js.map +1 -1
  318. package/dist/server/services/websocket/git-tag-handlers.d.ts.map +1 -1
  319. package/dist/server/services/websocket/git-tag-handlers.js +0 -1
  320. package/dist/server/services/websocket/git-tag-handlers.js.map +1 -1
  321. package/dist/server/services/websocket/git-utils.d.ts +18 -3
  322. package/dist/server/services/websocket/git-utils.d.ts.map +1 -1
  323. package/dist/server/services/websocket/git-utils.js +58 -8
  324. package/dist/server/services/websocket/git-utils.js.map +1 -1
  325. package/dist/server/services/websocket/git-worktree-handlers.d.ts.map +1 -1
  326. package/dist/server/services/websocket/git-worktree-handlers.js +258 -16
  327. package/dist/server/services/websocket/git-worktree-handlers.js.map +1 -1
  328. package/dist/server/services/websocket/handler-context.d.ts +15 -0
  329. package/dist/server/services/websocket/handler-context.d.ts.map +1 -1
  330. package/dist/server/services/websocket/handler-context.js +0 -1
  331. package/dist/server/services/websocket/handler-context.js.map +1 -1
  332. package/dist/server/services/websocket/handler.d.ts +7 -0
  333. package/dist/server/services/websocket/handler.d.ts.map +1 -1
  334. package/dist/server/services/websocket/handler.js +76 -15
  335. package/dist/server/services/websocket/handler.js.map +1 -1
  336. package/dist/server/services/websocket/index.d.ts.map +1 -1
  337. package/dist/server/services/websocket/index.js +0 -1
  338. package/dist/server/services/websocket/index.js.map +1 -1
  339. package/dist/server/services/websocket/msg-id-tracker.d.ts +21 -0
  340. package/dist/server/services/websocket/msg-id-tracker.d.ts.map +1 -0
  341. package/dist/server/services/websocket/msg-id-tracker.js +76 -0
  342. package/dist/server/services/websocket/msg-id-tracker.js.map +1 -0
  343. package/dist/server/services/websocket/plan-board-handlers.d.ts.map +1 -1
  344. package/dist/server/services/websocket/plan-board-handlers.js +0 -1
  345. package/dist/server/services/websocket/plan-board-handlers.js.map +1 -1
  346. package/dist/server/services/websocket/plan-execution-handlers.d.ts.map +1 -1
  347. package/dist/server/services/websocket/plan-execution-handlers.js +6 -2
  348. package/dist/server/services/websocket/plan-execution-handlers.js.map +1 -1
  349. package/dist/server/services/websocket/plan-handlers.d.ts.map +1 -1
  350. package/dist/server/services/websocket/plan-handlers.js +0 -1
  351. package/dist/server/services/websocket/plan-handlers.js.map +1 -1
  352. package/dist/server/services/websocket/plan-helpers.d.ts.map +1 -1
  353. package/dist/server/services/websocket/plan-helpers.js +0 -1
  354. package/dist/server/services/websocket/plan-helpers.js.map +1 -1
  355. package/dist/server/services/websocket/plan-issue-handlers.d.ts.map +1 -1
  356. package/dist/server/services/websocket/plan-issue-handlers.js +0 -1
  357. package/dist/server/services/websocket/plan-issue-handlers.js.map +1 -1
  358. package/dist/server/services/websocket/plan-sprint-handlers.d.ts.map +1 -1
  359. package/dist/server/services/websocket/plan-sprint-handlers.js +0 -1
  360. package/dist/server/services/websocket/plan-sprint-handlers.js.map +1 -1
  361. package/dist/server/services/websocket/quality-complexity.d.ts.map +1 -1
  362. package/dist/server/services/websocket/quality-complexity.js +0 -1
  363. package/dist/server/services/websocket/quality-complexity.js.map +1 -1
  364. package/dist/server/services/websocket/quality-grading.d.ts +46 -0
  365. package/dist/server/services/websocket/quality-grading.d.ts.map +1 -0
  366. package/dist/server/services/websocket/quality-grading.js +482 -0
  367. package/dist/server/services/websocket/quality-grading.js.map +1 -0
  368. package/dist/server/services/websocket/quality-handlers.d.ts.map +1 -1
  369. package/dist/server/services/websocket/quality-handlers.js +15 -4
  370. package/dist/server/services/websocket/quality-handlers.js.map +1 -1
  371. package/dist/server/services/websocket/quality-linting.d.ts.map +1 -1
  372. package/dist/server/services/websocket/quality-linting.js +0 -1
  373. package/dist/server/services/websocket/quality-linting.js.map +1 -1
  374. package/dist/server/services/websocket/quality-persistence.d.ts +14 -0
  375. package/dist/server/services/websocket/quality-persistence.d.ts.map +1 -1
  376. package/dist/server/services/websocket/quality-persistence.js +28 -12
  377. package/dist/server/services/websocket/quality-persistence.js.map +1 -1
  378. package/dist/server/services/websocket/quality-review-agent.d.ts.map +1 -1
  379. package/dist/server/services/websocket/quality-review-agent.js +2 -3
  380. package/dist/server/services/websocket/quality-review-agent.js.map +1 -1
  381. package/dist/server/services/websocket/quality-service.d.ts +3 -1
  382. package/dist/server/services/websocket/quality-service.d.ts.map +1 -1
  383. package/dist/server/services/websocket/quality-service.js +53 -58
  384. package/dist/server/services/websocket/quality-service.js.map +1 -1
  385. package/dist/server/services/websocket/quality-tools.d.ts +1 -1
  386. package/dist/server/services/websocket/quality-tools.d.ts.map +1 -1
  387. package/dist/server/services/websocket/quality-tools.js +6 -3
  388. package/dist/server/services/websocket/quality-tools.js.map +1 -1
  389. package/dist/server/services/websocket/quality-types.d.ts +18 -2
  390. package/dist/server/services/websocket/quality-types.d.ts.map +1 -1
  391. package/dist/server/services/websocket/quality-types.js +0 -1
  392. package/dist/server/services/websocket/quality-types.js.map +1 -1
  393. package/dist/server/services/websocket/session-handlers.d.ts +48 -2
  394. package/dist/server/services/websocket/session-handlers.d.ts.map +1 -1
  395. package/dist/server/services/websocket/session-handlers.js +204 -66
  396. package/dist/server/services/websocket/session-handlers.js.map +1 -1
  397. package/dist/server/services/websocket/session-history.d.ts.map +1 -1
  398. package/dist/server/services/websocket/session-history.js +0 -1
  399. package/dist/server/services/websocket/session-history.js.map +1 -1
  400. package/dist/server/services/websocket/session-initialization.d.ts +2 -2
  401. package/dist/server/services/websocket/session-initialization.d.ts.map +1 -1
  402. package/dist/server/services/websocket/session-initialization.js +75 -18
  403. package/dist/server/services/websocket/session-initialization.js.map +1 -1
  404. package/dist/server/services/websocket/session-registry.d.ts +29 -1
  405. package/dist/server/services/websocket/session-registry.d.ts.map +1 -1
  406. package/dist/server/services/websocket/session-registry.js +53 -5
  407. package/dist/server/services/websocket/session-registry.js.map +1 -1
  408. package/dist/server/services/websocket/settings-handlers.d.ts.map +1 -1
  409. package/dist/server/services/websocket/settings-handlers.js +0 -1
  410. package/dist/server/services/websocket/settings-handlers.js.map +1 -1
  411. package/dist/server/services/websocket/skill-handlers.d.ts.map +1 -1
  412. package/dist/server/services/websocket/skill-handlers.js +0 -1
  413. package/dist/server/services/websocket/skill-handlers.js.map +1 -1
  414. package/dist/server/services/websocket/skill-watcher.d.ts.map +1 -1
  415. package/dist/server/services/websocket/skill-watcher.js +0 -1
  416. package/dist/server/services/websocket/skill-watcher.js.map +1 -1
  417. package/dist/server/services/websocket/tab-broadcast.d.ts +24 -0
  418. package/dist/server/services/websocket/tab-broadcast.d.ts.map +1 -0
  419. package/dist/server/services/websocket/tab-broadcast.js +12 -0
  420. package/dist/server/services/websocket/tab-broadcast.js.map +1 -0
  421. package/dist/server/services/websocket/tab-event-buffer.d.ts +103 -0
  422. package/dist/server/services/websocket/tab-event-buffer.d.ts.map +1 -0
  423. package/dist/server/services/websocket/tab-event-buffer.js +106 -0
  424. package/dist/server/services/websocket/tab-event-buffer.js.map +1 -0
  425. package/dist/server/services/websocket/tab-event-replay.d.ts +20 -0
  426. package/dist/server/services/websocket/tab-event-replay.d.ts.map +1 -0
  427. package/dist/server/services/websocket/tab-event-replay.js +20 -0
  428. package/dist/server/services/websocket/tab-event-replay.js.map +1 -0
  429. package/dist/server/services/websocket/tab-handlers.d.ts +0 -1
  430. package/dist/server/services/websocket/tab-handlers.d.ts.map +1 -1
  431. package/dist/server/services/websocket/tab-handlers.js +2 -10
  432. package/dist/server/services/websocket/tab-handlers.js.map +1 -1
  433. package/dist/server/services/websocket/terminal-handlers.d.ts.map +1 -1
  434. package/dist/server/services/websocket/terminal-handlers.js +39 -4
  435. package/dist/server/services/websocket/terminal-handlers.js.map +1 -1
  436. package/dist/server/services/websocket/types.d.ts +17 -8
  437. package/dist/server/services/websocket/types.d.ts.map +1 -1
  438. package/dist/server/services/websocket/types.js +8 -7
  439. package/dist/server/services/websocket/types.js.map +1 -1
  440. package/dist/server/utils/agent-manager.d.ts.map +1 -1
  441. package/dist/server/utils/agent-manager.js +0 -1
  442. package/dist/server/utils/agent-manager.js.map +1 -1
  443. package/dist/server/utils/paths.d.ts.map +1 -1
  444. package/dist/server/utils/paths.js +0 -1
  445. package/dist/server/utils/paths.js.map +1 -1
  446. package/dist/server/utils/port-manager.d.ts.map +1 -1
  447. package/dist/server/utils/port-manager.js +0 -1
  448. package/dist/server/utils/port-manager.js.map +1 -1
  449. package/dist/server/utils/port.d.ts.map +1 -1
  450. package/dist/server/utils/port.js +0 -1
  451. package/dist/server/utils/port.js.map +1 -1
  452. package/package.json +2 -2
  453. package/server/README.md +1 -1
  454. package/server/cli/headless/claude-invoker-process.ts +0 -1
  455. package/server/cli/headless/claude-invoker-stall.ts +7 -3
  456. package/server/cli/headless/claude-invoker-stream.ts +0 -1
  457. package/server/cli/headless/claude-invoker-tools.ts +0 -1
  458. package/server/cli/headless/claude-invoker.ts +1 -2
  459. package/server/cli/headless/haiku-assessments.ts +0 -1
  460. package/server/cli/headless/headless-logger.ts +0 -1
  461. package/server/cli/headless/index.ts +0 -1
  462. package/server/cli/headless/native-timeout-detector.ts +0 -1
  463. package/server/cli/headless/output-utils.ts +0 -1
  464. package/server/cli/headless/prompt-utils.ts +0 -1
  465. package/server/cli/headless/resilient-runner.ts +0 -1
  466. package/server/cli/headless/retry-strategies.ts +0 -1
  467. package/server/cli/headless/runner.ts +67 -73
  468. package/server/cli/headless/stall-assessor.ts +9 -5
  469. package/server/cli/headless/tool-watchdog.ts +0 -1
  470. package/server/cli/headless/types.ts +1 -2
  471. package/server/cli/improvisation-attachments.ts +0 -1
  472. package/server/cli/improvisation-history-store.ts +61 -0
  473. package/server/cli/improvisation-movements.ts +119 -0
  474. package/server/cli/improvisation-output-queue.ts +41 -0
  475. package/server/cli/improvisation-retry.ts +25 -601
  476. package/server/cli/improvisation-session-manager.ts +74 -161
  477. package/server/cli/improvisation-types.ts +0 -1
  478. package/server/cli/retry/retry-best-result.ts +69 -0
  479. package/server/cli/retry/retry-context-loss.ts +86 -0
  480. package/server/cli/retry/retry-premature-completion.ts +112 -0
  481. package/server/cli/retry/retry-recovery-strategies.ts +246 -0
  482. package/server/cli/retry/retry-resume-strategy.ts +32 -0
  483. package/server/cli/retry/retry-runner-factory.ts +69 -0
  484. package/server/cli/retry/retry-tool-results.ts +30 -0
  485. package/server/cli/retry/retry-types.ts +31 -0
  486. package/server/index.ts +37 -124
  487. package/server/mcp/bouncer-cli.ts +0 -1
  488. package/server/mcp/bouncer-haiku.ts +0 -1
  489. package/server/mcp/bouncer-integration.ts +0 -1
  490. package/server/mcp/security-analysis.ts +0 -1
  491. package/server/mcp/security-audit.ts +0 -1
  492. package/server/mcp/security-patterns.ts +0 -1
  493. package/server/mcp/server.ts +0 -1
  494. package/server/routes/files.ts +0 -1
  495. package/server/routes/improvise.ts +0 -1
  496. package/server/routes/index.ts +0 -1
  497. package/server/routes/instances.ts +0 -1
  498. package/server/routes/notifications.ts +0 -1
  499. package/server/server-setup.ts +126 -2
  500. package/server/services/analytics.ts +0 -1
  501. package/server/services/auth.ts +0 -1
  502. package/server/services/client-id.ts +0 -1
  503. package/server/services/file-explorer-ops.ts +0 -1
  504. package/server/services/files.ts +0 -1
  505. package/server/services/instances.ts +0 -1
  506. package/server/services/pathUtils.ts +0 -1
  507. package/server/services/plan/agent-loader.ts +0 -1
  508. package/server/services/plan/agents/assess-stall.md +11 -4
  509. package/server/services/plan/agents/code-review.md +13 -11
  510. package/server/services/plan/board-config.ts +121 -0
  511. package/server/services/plan/composer.ts +7 -6
  512. package/server/services/plan/config-installer.ts +0 -1
  513. package/server/services/plan/dependency-resolver.ts +0 -1
  514. package/server/services/plan/executor.ts +259 -470
  515. package/server/services/plan/front-matter.ts +0 -1
  516. package/server/services/plan/issue-classification.ts +0 -1
  517. package/server/services/plan/issue-loader.ts +63 -0
  518. package/server/services/plan/issue-prompt-builder.ts +0 -1
  519. package/server/services/plan/issue-retry.ts +5 -2
  520. package/server/services/plan/issue-writer.ts +136 -0
  521. package/server/services/plan/output-manager.ts +2 -2
  522. package/server/services/plan/parser-core.ts +0 -1
  523. package/server/services/plan/parser-migration.ts +0 -1
  524. package/server/services/plan/parser.ts +0 -1
  525. package/server/services/plan/progress-log.ts +91 -0
  526. package/server/services/plan/prompt-builder.ts +73 -36
  527. package/server/services/plan/readiness-planner.ts +49 -0
  528. package/server/services/plan/review-gate.ts +102 -3
  529. package/server/services/plan/state-reconciler.ts +0 -1
  530. package/server/services/plan/types.ts +0 -1
  531. package/server/services/plan/watcher.ts +0 -1
  532. package/server/services/platform-credentials.ts +0 -1
  533. package/server/services/platform-token-lifecycle.ts +171 -0
  534. package/server/services/platform.ts +168 -105
  535. package/server/services/sentry.ts +0 -1
  536. package/server/services/settings.ts +0 -1
  537. package/server/services/terminal/pty-manager.ts +0 -1
  538. package/server/services/terminal/pty-utils.ts +0 -1
  539. package/server/services/websocket/autocomplete.ts +0 -1
  540. package/server/services/websocket/file-definition-handlers.ts +0 -1
  541. package/server/services/websocket/file-download-handler.ts +190 -0
  542. package/server/services/websocket/file-explorer-handlers.ts +0 -1
  543. package/server/services/websocket/file-search-handlers.ts +0 -1
  544. package/server/services/websocket/file-upload-handler.ts +6 -5
  545. package/server/services/websocket/file-utils.ts +0 -1
  546. package/server/services/websocket/git-branch-handlers.ts +0 -1
  547. package/server/services/websocket/git-diff-handlers.ts +0 -1
  548. package/server/services/websocket/git-handlers.ts +66 -10
  549. package/server/services/websocket/git-head-watcher.ts +0 -1
  550. package/server/services/websocket/git-log-handlers.ts +0 -1
  551. package/server/services/websocket/git-pr-handlers.ts +0 -1
  552. package/server/services/websocket/git-tag-handlers.ts +0 -1
  553. package/server/services/websocket/git-utils.ts +69 -9
  554. package/server/services/websocket/git-worktree-handlers.ts +289 -19
  555. package/server/services/websocket/handler-context.ts +15 -1
  556. package/server/services/websocket/handler.ts +79 -16
  557. package/server/services/websocket/index.ts +0 -1
  558. package/server/services/websocket/msg-id-tracker.ts +83 -0
  559. package/server/services/websocket/plan-board-handlers.ts +0 -1
  560. package/server/services/websocket/plan-execution-handlers.ts +6 -2
  561. package/server/services/websocket/plan-handlers.ts +0 -1
  562. package/server/services/websocket/plan-helpers.ts +0 -1
  563. package/server/services/websocket/plan-issue-handlers.ts +0 -1
  564. package/server/services/websocket/plan-sprint-handlers.ts +0 -1
  565. package/server/services/websocket/quality-complexity.ts +0 -1
  566. package/server/services/websocket/quality-grading.ts +611 -0
  567. package/server/services/websocket/quality-handlers.ts +16 -4
  568. package/server/services/websocket/quality-linting.ts +0 -1
  569. package/server/services/websocket/quality-persistence.ts +30 -8
  570. package/server/services/websocket/quality-review-agent.ts +2 -3
  571. package/server/services/websocket/quality-service.ts +54 -55
  572. package/server/services/websocket/quality-tools.ts +11 -3
  573. package/server/services/websocket/quality-types.ts +21 -3
  574. package/server/services/websocket/session-handlers.ts +213 -69
  575. package/server/services/websocket/session-history.ts +0 -1
  576. package/server/services/websocket/session-initialization.ts +83 -20
  577. package/server/services/websocket/session-registry.ts +61 -5
  578. package/server/services/websocket/settings-handlers.ts +0 -1
  579. package/server/services/websocket/skill-handlers.ts +0 -1
  580. package/server/services/websocket/skill-watcher.ts +0 -1
  581. package/server/services/websocket/tab-broadcast.ts +37 -0
  582. package/server/services/websocket/tab-event-buffer.ts +158 -0
  583. package/server/services/websocket/tab-event-replay.ts +41 -0
  584. package/server/services/websocket/tab-handlers.ts +2 -10
  585. package/server/services/websocket/terminal-handlers.ts +39 -3
  586. package/server/services/websocket/types.ts +19 -7
  587. package/server/utils/agent-manager.ts +0 -1
  588. package/server/utils/paths.ts +0 -1
  589. package/server/utils/port-manager.ts +0 -1
  590. package/server/utils/port.ts +0 -1
@@ -1,22 +1,41 @@
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
  * Improvisation Session Manager v2
6
5
  *
7
6
  * Optimized for fast, direct prompt execution in Improvise mode.
8
7
  * For complex multi-part prompts with parallel/sequential movements, use Compose tab instead.
8
+ *
9
+ * Delegates to focused helpers:
10
+ * - improvisation-output-queue.ts — buffered stdout flush loop
11
+ * - improvisation-history-store.ts — .mstro/history/*.json load/save
12
+ * - improvisation-movements.ts — pure movement-record builders
13
+ * - improvisation-retry.ts — retry decision tree + recovery strategies
9
14
  */
10
15
 
11
16
  import { EventEmitter } from 'node:events';
12
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
17
+ import { existsSync, readFileSync } from 'node:fs';
13
18
  import { join } from 'node:path';
14
19
  import { AnalyticsEvents, trackEvent } from '../services/analytics.js';
15
20
  import { herror } from './headless/headless-logger.js';
16
21
  import { cleanupAttachments, preparePromptAndAttachments } from './improvisation-attachments.js';
22
+ import {
23
+ ensureHistoryDir,
24
+ loadHistory,
25
+ resolveHistoryPaths,
26
+ saveHistory,
27
+ } from './improvisation-history-store.js';
28
+ import {
29
+ buildCancelledMovement,
30
+ buildErrorMovement,
31
+ buildSuccessMovement,
32
+ CANCELLED_FALLBACK_RESULT,
33
+ shouldAutoContinue,
34
+ } from './improvisation-movements.js';
35
+ import { OutputQueue } from './improvisation-output-queue.js';
17
36
  import type { RetryCallbacks, RetrySessionState } from './improvisation-retry.js';
18
- import {applyToolTimeoutRetry,
19
- createExecutionRunner,detectNativeTimeoutContextLoss, detectResumeContextLoss,
37
+ import {applyToolTimeoutRetry,
38
+ createExecutionRunner,detectNativeTimeoutContextLoss, detectResumeContextLoss,
20
39
  determineResumeStrategy,
21
40
  selectBestResult,
22
41
  shouldRetryContextLoss,
@@ -40,8 +59,7 @@ export class ImprovisationSessionManager extends EventEmitter {
40
59
  plan: unknown;
41
60
  resolve: (approved: boolean) => void;
42
61
  };
43
- private outputQueue: Array<{ text: string; timestamp: number }> = [];
44
- private queueTimer: NodeJS.Timeout | null = null;
62
+ private outputBuffer: OutputQueue;
45
63
  private isFirstPrompt: boolean = true;
46
64
  private claudeSessionId: string | undefined;
47
65
  private isResumedSession: boolean = false;
@@ -54,6 +72,7 @@ export class ImprovisationSessionManager extends EventEmitter {
54
72
  private _cancelCompleteEmitted: boolean = false;
55
73
  private _currentUserPrompt: string = '';
56
74
  private _currentSequenceNumber: number = 0;
75
+ private _hasPersistedToDisk: boolean = false;
57
76
 
58
77
  static resumeFromHistory(workingDir: string, historicalSessionId: string, overrides?: Partial<ImprovisationOptions>): ImprovisationSessionManager {
59
78
  const historyDir = join(workingDir, '.mstro', 'history');
@@ -79,6 +98,7 @@ export class ImprovisationSessionManager extends EventEmitter {
79
98
 
80
99
  manager.isResumedSession = true;
81
100
  manager.isFirstPrompt = true;
101
+ manager._hasPersistedToDisk = true;
82
102
  if (historyData.claudeSessionId) {
83
103
  manager.claudeSessionId = historyData.claudeSessionId;
84
104
  }
@@ -101,33 +121,29 @@ export class ImprovisationSessionManager extends EventEmitter {
101
121
  };
102
122
 
103
123
  this.sessionId = this.options.sessionId;
104
- this.improviseDir = join(this.options.workingDir, '.mstro', 'history');
105
- this.historyPath = join(this.improviseDir, `${this.sessionId.replace('improv-', '')}.json`);
124
+ const paths = resolveHistoryPaths(this.options.workingDir, this.sessionId);
125
+ this.improviseDir = paths.improviseDir;
126
+ this.historyPath = paths.historyPath;
127
+ ensureHistoryDir(this.improviseDir);
106
128
 
107
- if (!existsSync(this.improviseDir)) {
108
- mkdirSync(this.improviseDir, { recursive: true });
109
- }
129
+ this.history = loadHistory(this.historyPath, this.sessionId);
130
+ // History is persisted lazily on the first `persistHistory` call (see
131
+ // `executePrompt`). Deferring the initial write keeps the Chat History
132
+ // view from showing "0 prompts" entries for tabs the user opens but
133
+ // never prompts.
110
134
 
111
- this.history = this.loadHistory();
112
- this.saveHistory(); // Persist immediately so the session file exists on disk from creation
113
- this.startQueueProcessor();
135
+ this.outputBuffer = new OutputQueue(text => this.emit('onOutput', text));
136
+ this.outputBuffer.start();
114
137
  }
115
138
 
116
139
  // ========== Output Queue ==========
117
140
 
118
- private startQueueProcessor(): void {
119
- this.queueTimer = setInterval(() => { this.flushOutputQueue(); }, 50);
120
- }
121
-
122
141
  private queueOutput(text: string): void {
123
- this.outputQueue.push({ text, timestamp: Date.now() });
142
+ this.outputBuffer.queue_(text);
124
143
  }
125
144
 
126
145
  private flushOutputQueue(): void {
127
- while (this.outputQueue.length > 0) {
128
- const item = this.outputQueue.shift();
129
- if (item) this.emit('onOutput', item.text);
130
- }
146
+ this.outputBuffer.flush();
131
147
  }
132
148
 
133
149
  // ========== Main Execution ==========
@@ -174,7 +190,7 @@ export class ImprovisationSessionManager extends EventEmitter {
174
190
  ...(isAutoContinue && { isAutoContinue: true }),
175
191
  };
176
192
  this.history.movements.push(pendingMovement);
177
- this.saveHistory();
193
+ this.persistHistory();
178
194
 
179
195
  try {
180
196
  this.executionEventLog.push({
@@ -212,7 +228,11 @@ export class ImprovisationSessionManager extends EventEmitter {
212
228
  this.captureSessionAndSurfaceErrors(result);
213
229
  this.isFirstPrompt = false;
214
230
 
215
- const movement = this.buildMovementRecord(result, displayPrompt, sequenceNumber, _execStart, state.retryLog, isAutoContinue);
231
+ const movement = buildSuccessMovement(
232
+ result,
233
+ { sequenceNumber, userPrompt: displayPrompt, execStart: _execStart, isAutoContinue },
234
+ state.retryLog,
235
+ );
216
236
  this.handleConflicts(result);
217
237
  this.persistMovement(movement);
218
238
 
@@ -345,7 +365,14 @@ export class ImprovisationSessionManager extends EventEmitter {
345
365
  return false;
346
366
  }
347
367
 
348
- // ========== Cancel Handling ==========
368
+ // ========== Cancel / Error Handling ==========
369
+
370
+ private resetExecutionState(): void {
371
+ this._isExecuting = false;
372
+ this._executionStartTimestamp = undefined;
373
+ this.executionEventLog = [];
374
+ this.currentRunner = null;
375
+ }
349
376
 
350
377
  private handleCancelledExecution(
351
378
  result: HeadlessRunResult | undefined,
@@ -353,39 +380,16 @@ export class ImprovisationSessionManager extends EventEmitter {
353
380
  sequenceNumber: number,
354
381
  execStart: number,
355
382
  ): MovementRecord {
356
- this._isExecuting = false;
357
- this._executionStartTimestamp = undefined;
358
- this.executionEventLog = [];
359
- this.currentRunner = null;
383
+ this.resetExecutionState();
360
384
 
361
385
  if (this._cancelCompleteEmitted) {
362
386
  const existing = this.history.movements.find(m => m.sequenceNumber === sequenceNumber);
363
387
  if (existing) return existing;
364
388
  }
365
389
 
366
- const cancelledMovement: MovementRecord = {
367
- id: `prompt-${sequenceNumber}`,
368
- sequenceNumber,
369
- userPrompt,
370
- timestamp: new Date().toISOString(),
371
- tokensUsed: result ? result.totalTokens : 0,
372
- summary: '',
373
- filesModified: [],
374
- assistantResponse: result?.assistantResponse,
375
- thinkingOutput: result?.thinkingOutput,
376
- toolUseHistory: result?.toolUseHistory?.map(t => ({
377
- toolName: t.toolName, toolId: t.toolId, toolInput: t.toolInput,
378
- result: t.result,
379
- })),
380
- errorOutput: 'Execution cancelled by user',
381
- durationMs: Date.now() - execStart,
382
- };
390
+ const cancelledMovement = buildCancelledMovement(result, { sequenceNumber, userPrompt, execStart });
383
391
  this.persistMovement(cancelledMovement);
384
- const fallbackResult = {
385
- completed: false, needsHandoff: false, totalTokens: 0, sessionId: '',
386
- output: '', exitCode: 1, signalName: 'SIGTERM',
387
- } as HeadlessRunResult;
388
- this.emitMovementComplete(cancelledMovement, result ?? fallbackResult, execStart, sequenceNumber);
392
+ this.emitMovementComplete(cancelledMovement, result ?? CANCELLED_FALLBACK_RESULT, execStart, sequenceNumber);
389
393
  return cancelledMovement;
390
394
  }
391
395
 
@@ -395,23 +399,10 @@ export class ImprovisationSessionManager extends EventEmitter {
395
399
  sequenceNumber: number,
396
400
  execStart: number,
397
401
  ): never {
398
- this._isExecuting = false;
399
- this._executionStartTimestamp = undefined;
400
- this.executionEventLog = [];
401
- this.currentRunner = null;
402
+ this.resetExecutionState();
402
403
 
403
404
  const errorMessage = error instanceof Error ? error.message : String(error);
404
- const errorMovement: MovementRecord = {
405
- id: `prompt-${sequenceNumber}`,
406
- sequenceNumber,
407
- userPrompt: displayPrompt,
408
- timestamp: new Date().toISOString(),
409
- tokensUsed: 0,
410
- summary: '',
411
- filesModified: [],
412
- errorOutput: errorMessage,
413
- durationMs: Date.now() - execStart,
414
- };
405
+ const errorMovement = buildErrorMovement(errorMessage, { sequenceNumber, userPrompt: displayPrompt, execStart });
415
406
  this.persistMovement(errorMovement);
416
407
 
417
408
  this.emit('onMovementError', error);
@@ -440,35 +431,6 @@ export class ImprovisationSessionManager extends EventEmitter {
440
431
  }
441
432
  }
442
433
 
443
- private buildMovementRecord(
444
- result: HeadlessRunResult,
445
- userPrompt: string,
446
- sequenceNumber: number,
447
- execStart: number,
448
- retryLog?: import('./improvisation-types.js').RetryLogEntry[],
449
- isAutoContinue?: boolean,
450
- ): MovementRecord {
451
- return {
452
- id: `prompt-${sequenceNumber}`,
453
- sequenceNumber,
454
- userPrompt,
455
- timestamp: new Date().toISOString(),
456
- tokensUsed: result.totalTokens,
457
- summary: '',
458
- filesModified: [],
459
- assistantResponse: result.assistantResponse,
460
- thinkingOutput: result.thinkingOutput,
461
- toolUseHistory: result.toolUseHistory?.map(t => ({
462
- toolName: t.toolName, toolId: t.toolId, toolInput: t.toolInput,
463
- result: t.result, isError: t.isError, duration: t.duration,
464
- })),
465
- errorOutput: result.error,
466
- durationMs: Date.now() - execStart,
467
- retryLog: retryLog && retryLog.length > 0 ? retryLog : undefined,
468
- ...(isAutoContinue && { isAutoContinue: true }),
469
- };
470
- }
471
-
472
434
  private handleConflicts(result: HeadlessRunResult): void {
473
435
  if (!result.conflicts || result.conflicts.length === 0) return;
474
436
  this.queueOutput(`\n⚠ File conflicts detected: ${result.conflicts.length}`);
@@ -489,7 +451,7 @@ export class ImprovisationSessionManager extends EventEmitter {
489
451
  this.history.movements.push(movement);
490
452
  this.history.totalTokens += movement.tokensUsed;
491
453
  }
492
- this.saveHistory();
454
+ this.persistHistory();
493
455
  }
494
456
 
495
457
  private emitMovementComplete(movement: MovementRecord, result: HeadlessRunResult, execStart: number, sequenceNumber: number): void {
@@ -515,26 +477,10 @@ export class ImprovisationSessionManager extends EventEmitter {
515
477
  const isStallKill = !this._cancelled && !!result.signalName;
516
478
  if (isStallKill && this._autoContinueCount < ImprovisationSessionManager.MAX_AUTO_CONTINUES) {
517
479
  this.scheduleAutoContinue('Process stalled');
518
- } else if (this.shouldAutoContinue(result, userPrompt)) {
480
+ } else if (shouldAutoContinue(result, this._autoContinueCount, ImprovisationSessionManager.MAX_AUTO_CONTINUES, this._cancelled)) {
519
481
  this.scheduleAutoContinue();
520
482
  }
521
- }
522
-
523
- private shouldAutoContinue(result: HeadlessRunResult, _userPrompt: string): boolean {
524
- if (this._autoContinueCount >= ImprovisationSessionManager.MAX_AUTO_CONTINUES) return false;
525
- if (this._cancelled) return false;
526
- if (!result.completed || result.signalName) return false;
527
- if (result.stopReason !== 'end_turn') return false;
528
-
529
- const thinkingLen = result.thinkingOutput?.length ?? 0;
530
- const responseLen = result.assistantResponse?.length ?? 0;
531
- const successfulToolCalls = result.toolUseHistory?.filter(t => t.result !== undefined && !t.isError).length ?? 0;
532
-
533
- if (thinkingLen < 500 || responseLen > 1000) return false;
534
- // When the agent executed tool calls and produced a non-trivial response,
535
- // long thinking is expected — the work happened in the tools, not the text.
536
- if (successfulToolCalls > 0 && responseLen > 200) return false;
537
- return thinkingLen >= responseLen * 3;
483
+ void userPrompt;
538
484
  }
539
485
 
540
486
  private scheduleAutoContinue(reason?: string): void {
@@ -555,27 +501,12 @@ export class ImprovisationSessionManager extends EventEmitter {
555
501
 
556
502
  // ========== History I/O ==========
557
503
 
558
- private loadHistory(): SessionHistory {
559
- if (existsSync(this.historyPath)) {
560
- try {
561
- const data = readFileSync(this.historyPath, 'utf-8');
562
- return JSON.parse(data);
563
- } catch (error) {
564
- herror('Failed to load history:', error);
565
- }
504
+ private persistHistory(): void {
505
+ saveHistory(this.historyPath, this.history);
506
+ if (!this._hasPersistedToDisk) {
507
+ this._hasPersistedToDisk = true;
508
+ this.emit('onHistoryPersisted');
566
509
  }
567
- return {
568
- sessionId: this.sessionId,
569
- startedAt: new Date().toISOString(),
570
- lastActivityAt: new Date().toISOString(),
571
- totalTokens: 0,
572
- movements: [],
573
- };
574
- }
575
-
576
- private saveHistory(): void {
577
- this.history.lastActivityAt = new Date().toISOString();
578
- writeFileSync(this.historyPath, JSON.stringify(this.history, null, 2));
579
510
  }
580
511
 
581
512
  getHistory(): SessionHistory {
@@ -592,7 +523,7 @@ export class ImprovisationSessionManager extends EventEmitter {
592
523
  this.currentRunner = null;
593
524
  }
594
525
 
595
- this.destroyQueueTimer();
526
+ this.outputBuffer.destroy();
596
527
 
597
528
  if (this._isExecuting && !this._cancelCompleteEmitted) {
598
529
  this._cancelCompleteEmitted = true;
@@ -600,38 +531,20 @@ export class ImprovisationSessionManager extends EventEmitter {
600
531
  this._isExecuting = false;
601
532
  this._executionStartTimestamp = undefined;
602
533
 
603
- const cancelledMovement: MovementRecord = {
604
- id: `prompt-${this._currentSequenceNumber}`,
534
+ const cancelledMovement = buildCancelledMovement(undefined, {
605
535
  sequenceNumber: this._currentSequenceNumber,
606
536
  userPrompt: this._currentUserPrompt,
607
- timestamp: new Date().toISOString(),
608
- tokensUsed: 0,
609
- summary: '',
610
- filesModified: [],
611
- errorOutput: 'Execution cancelled by user',
612
- durationMs: Date.now() - execStart,
613
- };
537
+ execStart,
538
+ });
614
539
  this.persistMovement(cancelledMovement);
615
-
616
- const fallbackResult = {
617
- completed: false, needsHandoff: false, totalTokens: 0, sessionId: '',
618
- output: '', exitCode: 1, signalName: 'SIGTERM',
619
- } as HeadlessRunResult;
620
- this.emitMovementComplete(cancelledMovement, fallbackResult, execStart, this._currentSequenceNumber);
540
+ this.emitMovementComplete(cancelledMovement, CANCELLED_FALLBACK_RESULT, execStart, this._currentSequenceNumber);
621
541
  }
622
542
 
623
543
  this.flushOutputQueue();
624
544
  }
625
545
 
626
- private destroyQueueTimer(): void {
627
- if (this.queueTimer) {
628
- clearInterval(this.queueTimer);
629
- this.queueTimer = null;
630
- }
631
- }
632
-
633
546
  destroy(): void {
634
- this.destroyQueueTimer();
547
+ this.outputBuffer.destroy();
635
548
  this.flushOutputQueue();
636
549
  }
637
550
 
@@ -642,7 +555,7 @@ export class ImprovisationSessionManager extends EventEmitter {
642
555
  this.isFirstPrompt = true;
643
556
  this.claudeSessionId = undefined;
644
557
  cleanupAttachments(this.options.workingDir, this.sessionId);
645
- this.saveHistory();
558
+ this.persistHistory();
646
559
  this.emit('onSessionUpdate', this.getHistory());
647
560
  }
648
561
 
@@ -684,7 +597,7 @@ export class ImprovisationSessionManager extends EventEmitter {
684
597
  }
685
598
 
686
599
  startNewSession(overrides?: Partial<ImprovisationOptions>): ImprovisationSessionManager {
687
- this.saveHistory();
600
+ this.persistHistory();
688
601
  return new ImprovisationSessionManager({
689
602
  ...this.options,
690
603
  sessionId: `improv-${Date.now()}`,
@@ -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
  * Types and interfaces for the Improvisation Session Manager.
@@ -0,0 +1,69 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+
3
+ /**
4
+ * Picks the best result across retry attempts. Prefers Haiku's judgment
5
+ * when available; falls back to a numeric score when Haiku is unreachable.
6
+ */
7
+
8
+ import { hlog } from '../headless/headless-logger.js';
9
+ import { assessBestResult } from '../headless/stall-assessor.js';
10
+ import type { HeadlessRunResult, RetryLoopState } from '../improvisation-types.js';
11
+ import { scoreRunResult } from '../improvisation-types.js';
12
+
13
+ /** Select the best result across retries using Haiku assessment */
14
+ export async function selectBestResult(
15
+ state: RetryLoopState,
16
+ result: HeadlessRunResult,
17
+ userPrompt: string,
18
+ verbose: boolean,
19
+ ): Promise<HeadlessRunResult> {
20
+ if (!state.bestResult || state.bestResult === result || state.retryNumber === 0) {
21
+ return result;
22
+ }
23
+
24
+ const claudeCmd = process.env.CLAUDE_COMMAND || 'claude';
25
+ const bestToolCount = state.bestResult.toolUseHistory?.filter(t => t.result !== undefined && !t.isError).length ?? 0;
26
+ const currentToolCount = result.toolUseHistory?.filter(t => t.result !== undefined && !t.isError).length ?? 0;
27
+
28
+ try {
29
+ const verdict = await assessBestResult({
30
+ originalPrompt: userPrompt,
31
+ resultA: {
32
+ successfulToolCalls: bestToolCount,
33
+ responseLength: state.bestResult.assistantResponse?.length ?? 0,
34
+ hasThinking: !!state.bestResult.thinkingOutput,
35
+ responseTail: (state.bestResult.assistantResponse ?? '').slice(-500),
36
+ },
37
+ resultB: {
38
+ successfulToolCalls: currentToolCount,
39
+ responseLength: result.assistantResponse?.length ?? 0,
40
+ hasThinking: !!result.thinkingOutput,
41
+ responseTail: (result.assistantResponse ?? '').slice(-500),
42
+ },
43
+ }, claudeCmd, verbose);
44
+
45
+ if (verdict.winner === 'A') {
46
+ if (verbose) hlog(`[BEST-RESULT] Haiku picked earlier attempt: ${verdict.reason}`);
47
+ return mergeResultSessionId(state.bestResult, result.claudeSessionId);
48
+ }
49
+ if (verbose) hlog(`[BEST-RESULT] Haiku picked final attempt: ${verdict.reason}`);
50
+ return result;
51
+ } catch {
52
+ return fallbackBestResult(state.bestResult, result, verbose);
53
+ }
54
+ }
55
+
56
+ function mergeResultSessionId(result: HeadlessRunResult, sessionId: string | undefined): HeadlessRunResult {
57
+ if (sessionId) return { ...result, claudeSessionId: sessionId };
58
+ return result;
59
+ }
60
+
61
+ function fallbackBestResult(bestResult: HeadlessRunResult, result: HeadlessRunResult, verbose: boolean): HeadlessRunResult {
62
+ if (scoreRunResult(bestResult) > scoreRunResult(result)) {
63
+ if (verbose) {
64
+ hlog(`[BEST-RESULT] Haiku unavailable, numeric fallback: earlier attempt (score ${scoreRunResult(bestResult)} vs ${scoreRunResult(result)})`);
65
+ }
66
+ return mergeResultSessionId(bestResult, result.claudeSessionId);
67
+ }
68
+ return result;
69
+ }
@@ -0,0 +1,86 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+
3
+ /**
4
+ * Context-loss detection: figures out when a run's output indicates the
5
+ * Claude session dropped its memory, either on `--resume` (Path 1) or after
6
+ * native tool timeouts scrambled the conversation (Path 2).
7
+ */
8
+
9
+ import { hlog } from '../headless/headless-logger.js';
10
+ import { assessContextLoss, type ContextLossContext } from '../headless/stall-assessor.js';
11
+ import type { HeadlessRunResult, RetryLoopState } from '../improvisation-types.js';
12
+
13
+ const WRITE_TOOL_NAMES = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit']);
14
+
15
+ /** Detect resume context loss (Path 1): session expired on --resume */
16
+ export function detectResumeContextLoss(
17
+ result: HeadlessRunResult,
18
+ state: RetryLoopState,
19
+ useResume: boolean,
20
+ maxRetries: number,
21
+ nativeTimeouts: number,
22
+ verbose: boolean,
23
+ ): void {
24
+ if (!useResume || state.checkpointRef.value || state.retryNumber >= maxRetries || nativeTimeouts > 0) {
25
+ return;
26
+ }
27
+ if (!result.assistantResponse || result.assistantResponse.trim().length === 0) {
28
+ state.contextLost = true;
29
+ if (verbose) hlog('[CONTEXT-RECOVERY] Resume context loss: null/empty response');
30
+ } else if (result.resumeBufferedOutput !== undefined) {
31
+ state.contextLost = true;
32
+ if (verbose) hlog('[CONTEXT-RECOVERY] Resume context loss: buffer never flushed (no thinking/tools)');
33
+ } else if (
34
+ (!result.toolUseHistory || result.toolUseHistory.length === 0) &&
35
+ !result.thinkingOutput &&
36
+ result.assistantResponse.length < 500
37
+ ) {
38
+ state.contextLost = true;
39
+ if (verbose) hlog('[CONTEXT-RECOVERY] Resume context loss: no tools, no thinking, short response');
40
+ }
41
+ }
42
+
43
+ /** Detect native timeout context loss (Path 2): tool timeouts caused confusion */
44
+ export async function detectNativeTimeoutContextLoss(
45
+ result: HeadlessRunResult,
46
+ state: RetryLoopState,
47
+ maxRetries: number,
48
+ nativeTimeouts: number,
49
+ verbose: boolean,
50
+ ): Promise<void> {
51
+ if (state.contextLost) return;
52
+
53
+ const { effectiveTimeouts } = computeEffectiveTimeouts(result, nativeTimeouts);
54
+ if (effectiveTimeouts === 0 || !result.assistantResponse || state.checkpointRef.value || state.retryNumber >= maxRetries) {
55
+ return;
56
+ }
57
+
58
+ const contextLossCtx: ContextLossContext = {
59
+ assistantResponse: result.assistantResponse,
60
+ effectiveTimeouts,
61
+ nativeTimeoutCount: nativeTimeouts,
62
+ successfulToolCalls: result.toolUseHistory?.filter(t => t.result !== undefined && !t.isError).length ?? 0,
63
+ thinkingOutputLength: result.thinkingOutput?.length ?? 0,
64
+ hasSuccessfulWrite: result.toolUseHistory?.some(
65
+ t => WRITE_TOOL_NAMES.has(t.toolName) && t.result !== undefined && !t.isError
66
+ ) ?? false,
67
+ };
68
+
69
+ const claudeCmd = process.env.CLAUDE_COMMAND || 'claude';
70
+ const verdict = await assessContextLoss(contextLossCtx, claudeCmd, verbose);
71
+ state.contextLost = verdict.contextLost;
72
+ if (verbose) {
73
+ hlog(`[CONTEXT-RECOVERY] Haiku verdict: ${state.contextLost ? 'LOST' : 'OK'} — ${verdict.reason}`);
74
+ }
75
+ }
76
+
77
+ function computeEffectiveTimeouts(result: HeadlessRunResult, nativeTimeouts: number): { effectiveTimeouts: number } {
78
+ const succeededIds = new Set<string>();
79
+ const allIds = new Set<string>();
80
+ for (const t of result.toolUseHistory ?? []) {
81
+ allIds.add(t.toolId);
82
+ if (t.result !== undefined) succeededIds.add(t.toolId);
83
+ }
84
+ const toolsWithoutResult = [...allIds].filter(id => !succeededIds.has(id)).length;
85
+ return { effectiveTimeouts: Math.max(nativeTimeouts, toolsWithoutResult) };
86
+ }
@@ -0,0 +1,112 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+
3
+ /**
4
+ * Detects when a claimed-complete run is actually unfinished (hit
5
+ * max_tokens, abandoned mid-task, or Haiku says the end_turn response is
6
+ * a stop short of the goal) and triggers a continuation retry.
7
+ */
8
+
9
+ import { AnalyticsEvents, trackEvent } from '../../services/analytics.js';
10
+ import { hlog } from '../headless/headless-logger.js';
11
+ import { extractFinalTextBlock, isResponseAbandoned } from '../headless/retry-strategies.js';
12
+ import { assessPrematureCompletion } from '../headless/stall-assessor.js';
13
+ import type { HeadlessRunResult, RetryLoopState } from '../improvisation-types.js';
14
+ import type { RetryCallbacks, RetrySessionState } from './retry-types.js';
15
+
16
+ /** Guard checks for premature completion */
17
+ function isPrematureCompletionCandidate(
18
+ result: HeadlessRunResult,
19
+ state: RetryLoopState,
20
+ maxRetries: number,
21
+ ): boolean {
22
+ if (!result.completed || result.signalName || state.retryNumber >= maxRetries) return false;
23
+ if (state.checkpointRef.value || state.contextLost) return false;
24
+ if (!result.claudeSessionId || !result.stopReason) return false;
25
+ return result.stopReason === 'max_tokens' || result.stopReason === 'end_turn';
26
+ }
27
+
28
+ /** Use Haiku to assess whether an end_turn response is genuinely complete */
29
+ async function assessEndTurnCompletion(result: HeadlessRunResult, verbose: boolean): Promise<boolean> {
30
+ if (!result.assistantResponse) return false;
31
+
32
+ const successfulToolCalls = result.toolUseHistory?.filter(t => t.result !== undefined && !t.isError).length ?? 0;
33
+ const claudeCmd = process.env.CLAUDE_COMMAND || 'claude';
34
+ const verdict = await assessPrematureCompletion({
35
+ responseTail: extractFinalTextBlock(result.assistantResponse, 800),
36
+ successfulToolCalls,
37
+ hasThinking: !!result.thinkingOutput,
38
+ responseLength: result.assistantResponse.length,
39
+ }, claudeCmd, verbose);
40
+
41
+ if (verbose) {
42
+ hlog(`[PREMATURE-COMPLETION] Haiku verdict: ${verdict.isIncomplete ? 'INCOMPLETE' : 'COMPLETE'} — ${verdict.reason}`);
43
+ }
44
+ return verdict.isIncomplete;
45
+ }
46
+
47
+ /** Apply premature completion retry */
48
+ function applyPrematureCompletionRetry(
49
+ result: HeadlessRunResult,
50
+ state: RetryLoopState,
51
+ session: RetrySessionState,
52
+ maxRetries: number,
53
+ stopReason: string,
54
+ isMaxTokens: boolean,
55
+ callbacks: RetryCallbacks,
56
+ ): void {
57
+ state.retryNumber++;
58
+ const reason = isMaxTokens ? 'Output limit reached' : 'Task appears unfinished (AI assessment)';
59
+
60
+ state.retryLog.push({
61
+ retryNumber: state.retryNumber,
62
+ path: 'PrematureCompletion',
63
+ reason,
64
+ timestamp: Date.now(),
65
+ });
66
+
67
+ callbacks.emit('onAutoRetry', {
68
+ retryNumber: state.retryNumber,
69
+ maxRetries,
70
+ toolName: `PrematureCompletion(${stopReason})`,
71
+ completedCount: result.toolUseHistory?.length ?? 0,
72
+ });
73
+
74
+ trackEvent(AnalyticsEvents.IMPROVISE_AUTO_RETRY, {
75
+ retry_number: state.retryNumber,
76
+ hung_tool: `premature_completion:${stopReason}`,
77
+ completed_tools: result.toolUseHistory?.length ?? 0,
78
+ resume_attempted: true,
79
+ });
80
+
81
+ callbacks.queueOutput(
82
+ `\n\n${reason} — resuming session (retry ${state.retryNumber}/${maxRetries}).\n\n`
83
+ );
84
+ callbacks.flushOutputQueue();
85
+
86
+ state.contextRecoverySessionId = result.claudeSessionId;
87
+ session.claudeSessionId = result.claudeSessionId;
88
+ state.currentPrompt = 'continue';
89
+ }
90
+
91
+ /** Detect and retry premature completion. Returns true if loop should continue. */
92
+ export async function shouldRetryPrematureCompletion(
93
+ result: HeadlessRunResult,
94
+ state: RetryLoopState,
95
+ session: RetrySessionState,
96
+ maxRetries: number,
97
+ callbacks: RetryCallbacks,
98
+ ): Promise<boolean> {
99
+ if (!isPrematureCompletionCandidate(result, state, maxRetries)) {
100
+ return false;
101
+ }
102
+
103
+ const stopReason = result.stopReason!;
104
+ const isMaxTokens = stopReason === 'max_tokens';
105
+ const abandoned = isResponseAbandoned(result);
106
+ const isIncomplete = isMaxTokens || abandoned || await assessEndTurnCompletion(result, session.options.verbose);
107
+
108
+ if (!isIncomplete) return false;
109
+
110
+ applyPrematureCompletionRetry(result, state, session, maxRetries, stopReason, isMaxTokens, callbacks);
111
+ return true;
112
+ }