@stigmer/runner 3.14.1 → 3.15.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 (320) hide show
  1. package/dist/.build-fingerprint +1 -1
  2. package/dist/__test-utils__/execution-record-fixture.d.ts +47 -0
  3. package/dist/__test-utils__/execution-record-fixture.js +68 -0
  4. package/dist/__test-utils__/execution-record-fixture.js.map +1 -0
  5. package/dist/__test-utils__/harness-contract/types.d.ts +166 -0
  6. package/dist/__test-utils__/harness-contract/types.js +49 -0
  7. package/dist/__test-utils__/harness-contract/types.js.map +1 -0
  8. package/dist/__test-utils__/hermetic-activity.d.ts +28 -5
  9. package/dist/__test-utils__/hermetic-activity.js +23 -7
  10. package/dist/__test-utils__/hermetic-activity.js.map +1 -1
  11. package/dist/__test-utils__/mock-workspace.d.ts +15 -0
  12. package/dist/__test-utils__/mock-workspace.js +21 -0
  13. package/dist/__test-utils__/mock-workspace.js.map +1 -0
  14. package/dist/__test-utils__/model-registry-fixture.d.ts +56 -0
  15. package/dist/__test-utils__/model-registry-fixture.js +66 -0
  16. package/dist/__test-utils__/model-registry-fixture.js.map +1 -0
  17. package/dist/__test-utils__/turn-input-fixture.d.ts +60 -0
  18. package/dist/__test-utils__/turn-input-fixture.js +118 -0
  19. package/dist/__test-utils__/turn-input-fixture.js.map +1 -0
  20. package/dist/activities/execute-cursor/__test-utils__/contract-subject.d.ts +107 -0
  21. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js +344 -0
  22. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js.map +1 -0
  23. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.d.ts +20 -0
  24. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js +58 -0
  25. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js.map +1 -1
  26. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js +2 -32
  27. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js.map +1 -1
  28. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +38 -62
  29. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +47 -121
  30. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
  31. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.d.ts +17 -1
  32. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js +27 -4
  33. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js.map +1 -1
  34. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.d.ts +52 -11
  35. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js +66 -7
  36. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js.map +1 -1
  37. package/dist/activities/execute-cursor/adapter.d.ts +55 -0
  38. package/dist/activities/execute-cursor/adapter.js +119 -0
  39. package/dist/activities/execute-cursor/adapter.js.map +1 -0
  40. package/dist/activities/execute-cursor/approval-state.d.ts +2 -2
  41. package/dist/activities/execute-cursor/approval-state.js.map +1 -1
  42. package/dist/activities/execute-cursor/capture-flow.d.ts +15 -30
  43. package/dist/activities/execute-cursor/capture-flow.js +17 -26
  44. package/dist/activities/execute-cursor/capture-flow.js.map +1 -1
  45. package/dist/activities/execute-cursor/cursor-capabilities.d.ts +23 -0
  46. package/dist/activities/execute-cursor/cursor-capabilities.js +33 -0
  47. package/dist/activities/execute-cursor/cursor-capabilities.js.map +1 -0
  48. package/dist/activities/execute-cursor/cursor-mcp-config.d.ts +2 -2
  49. package/dist/activities/execute-cursor/cursor-mcp-config.js.map +1 -1
  50. package/dist/activities/execute-cursor/fetch-interceptor.d.ts +15 -25
  51. package/dist/activities/execute-cursor/fetch-interceptor.js +39 -33
  52. package/dist/activities/execute-cursor/fetch-interceptor.js.map +1 -1
  53. package/dist/activities/execute-cursor/http2-interceptor.d.ts +21 -17
  54. package/dist/activities/execute-cursor/http2-interceptor.js +38 -31
  55. package/dist/activities/execute-cursor/http2-interceptor.js.map +1 -1
  56. package/dist/activities/execute-cursor/message-translator.d.ts +28 -19
  57. package/dist/activities/execute-cursor/message-translator.js +76 -27
  58. package/dist/activities/execute-cursor/message-translator.js.map +1 -1
  59. package/dist/activities/execute-cursor/prompt-builder.d.ts +180 -11
  60. package/dist/activities/execute-cursor/prompt-builder.js +171 -0
  61. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  62. package/dist/activities/execute-cursor/rejection-capture.d.ts +3 -6
  63. package/dist/activities/execute-cursor/rejection-capture.js +5 -7
  64. package/dist/activities/execute-cursor/rejection-capture.js.map +1 -1
  65. package/dist/activities/execute-cursor/session-lifecycle.d.ts +1 -4
  66. package/dist/activities/execute-cursor/session-lifecycle.js.map +1 -1
  67. package/dist/activities/execute-cursor/turn-boundary.d.ts +1 -1
  68. package/dist/activities/execute-cursor/turn-settle.d.ts +49 -0
  69. package/dist/activities/execute-cursor/turn-settle.js +507 -0
  70. package/dist/activities/execute-cursor/turn-settle.js.map +1 -0
  71. package/dist/activities/execute-cursor/turn-setup.d.ts +173 -0
  72. package/dist/activities/execute-cursor/turn-setup.js +496 -0
  73. package/dist/activities/execute-cursor/turn-setup.js.map +1 -0
  74. package/dist/activities/execute-cursor/turn-stream.d.ts +41 -71
  75. package/dist/activities/execute-cursor/turn-stream.js +70 -135
  76. package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
  77. package/dist/activities/execute-cursor/turn.d.ts +43 -0
  78. package/dist/activities/execute-cursor/turn.js +222 -0
  79. package/dist/activities/execute-cursor/turn.js.map +1 -0
  80. package/dist/activities/execute-cursor/usage-pricing.d.ts +38 -0
  81. package/dist/activities/execute-cursor/usage-pricing.js +50 -0
  82. package/dist/activities/execute-cursor/usage-pricing.js.map +1 -0
  83. package/dist/activities/execute-deep-agent/approval-file-change.d.ts +1 -1
  84. package/dist/activities/execute-deep-agent/approval-file-change.js +1 -1
  85. package/dist/activities/execute-deep-agent/environment.js +1 -1
  86. package/dist/activities/execute-deep-agent/environment.js.map +1 -1
  87. package/dist/activities/execute-deep-agent/setup.js +3 -2
  88. package/dist/activities/execute-deep-agent/setup.js.map +1 -1
  89. package/dist/activities/hydrate-workflow-execution.js +1 -1
  90. package/dist/activities/hydrate-workflow-execution.js.map +1 -1
  91. package/dist/config.d.ts +15 -0
  92. package/dist/config.js.map +1 -1
  93. package/dist/harness/capabilities.d.ts +16 -0
  94. package/dist/harness/capabilities.js +1 -0
  95. package/dist/harness/capabilities.js.map +1 -1
  96. package/dist/harness/persist-chokepoint.d.ts +74 -0
  97. package/dist/harness/persist-chokepoint.js +88 -0
  98. package/dist/harness/persist-chokepoint.js.map +1 -0
  99. package/dist/harness/registry.d.ts +44 -5
  100. package/dist/harness/registry.js +61 -5
  101. package/dist/harness/registry.js.map +1 -1
  102. package/dist/harness/run-turn.d.ts +53 -0
  103. package/dist/harness/run-turn.js +528 -0
  104. package/dist/harness/run-turn.js.map +1 -0
  105. package/dist/harness/stop-controller.d.ts +50 -0
  106. package/dist/harness/stop-controller.js +62 -0
  107. package/dist/harness/stop-controller.js.map +1 -0
  108. package/dist/harness/terminal-table.d.ts +141 -0
  109. package/dist/harness/terminal-table.js +239 -0
  110. package/dist/harness/terminal-table.js.map +1 -0
  111. package/dist/harness/turn-context.d.ts +523 -0
  112. package/dist/harness/turn-context.js +739 -0
  113. package/dist/harness/turn-context.js.map +1 -0
  114. package/dist/harness/types.d.ts +232 -52
  115. package/dist/harness/types.js +17 -8
  116. package/dist/harness/types.js.map +1 -1
  117. package/dist/harness/usage-accumulator.d.ts +68 -0
  118. package/dist/harness/usage-accumulator.js +101 -0
  119. package/dist/harness/usage-accumulator.js.map +1 -0
  120. package/dist/harness-adapters.d.ts +27 -0
  121. package/dist/harness-adapters.js +28 -0
  122. package/dist/harness-adapters.js.map +1 -0
  123. package/dist/main.js.map +1 -1
  124. package/dist/runner-manager.js +64 -48
  125. package/dist/runner-manager.js.map +1 -1
  126. package/dist/runner.d.ts +5 -4
  127. package/dist/runner.js +65 -64
  128. package/dist/runner.js.map +1 -1
  129. package/dist/shared/approval-policy.d.ts +1 -1
  130. package/dist/shared/approval-policy.js.map +1 -1
  131. package/dist/{activities/execute-cursor → shared}/attachment-resolver.d.ts +2 -2
  132. package/dist/{activities/execute-cursor → shared}/attachment-resolver.js +5 -5
  133. package/dist/shared/attachment-resolver.js.map +1 -0
  134. package/dist/{activities/execute-cursor → shared}/blueprint-resolver.d.ts +7 -5
  135. package/dist/{activities/execute-cursor → shared}/blueprint-resolver.js +3 -63
  136. package/dist/shared/blueprint-resolver.js.map +1 -0
  137. package/dist/shared/channel-attachment.d.ts +1 -1
  138. package/dist/shared/channel-attachment.js.map +1 -1
  139. package/dist/{activities/execute-cursor → shared}/cost-guard.d.ts +5 -1
  140. package/dist/{activities/execute-cursor → shared}/cost-guard.js +5 -1
  141. package/dist/shared/cost-guard.js.map +1 -0
  142. package/dist/{activities/execute-cursor → shared}/env-resolver.d.ts +1 -1
  143. package/dist/shared/env-resolver.js.map +1 -0
  144. package/dist/{activities/execute-cursor → shared}/exact-apply.d.ts +1 -1
  145. package/dist/{activities/execute-cursor → shared}/exact-apply.js +6 -6
  146. package/dist/shared/exact-apply.js.map +1 -0
  147. package/dist/shared/execution-context.d.ts +35 -0
  148. package/dist/shared/execution-context.js +38 -0
  149. package/dist/shared/execution-context.js.map +1 -0
  150. package/dist/{activities/execute-cursor → shared}/extract-structured-output.d.ts +5 -2
  151. package/dist/{activities/execute-cursor → shared}/extract-structured-output.js +9 -6
  152. package/dist/shared/extract-structured-output.js.map +1 -0
  153. package/dist/shared/filereview/capture.d.ts +1 -1
  154. package/dist/shared/filereview/capture.js +1 -1
  155. package/dist/shared/heartbeat.d.ts +13 -11
  156. package/dist/shared/heartbeat.js +14 -29
  157. package/dist/shared/heartbeat.js.map +1 -1
  158. package/dist/{activities/execute-cursor → shared}/persist-decision.d.ts +5 -2
  159. package/dist/{activities/execute-cursor → shared}/persist-decision.js +4 -1
  160. package/dist/shared/persist-decision.js.map +1 -0
  161. package/dist/{activities/execute-cursor → shared}/skill-resolver.d.ts +16 -3
  162. package/dist/{activities/execute-cursor → shared}/skill-resolver.js +12 -4
  163. package/dist/shared/skill-resolver.js.map +1 -0
  164. package/dist/shared/subagent-rows.d.ts +21 -0
  165. package/dist/shared/subagent-rows.js +34 -0
  166. package/dist/shared/subagent-rows.js.map +1 -0
  167. package/dist/shared/worker-shutdown.d.ts +43 -16
  168. package/dist/shared/worker-shutdown.js +28 -13
  169. package/dist/shared/worker-shutdown.js.map +1 -1
  170. package/dist/shared/workspace/platform-dir.d.ts +1 -1
  171. package/dist/shared/workspace/platform-dir.js +1 -1
  172. package/dist/shared/workspace/session-provision.d.ts +54 -0
  173. package/dist/{activities/execute-cursor/workspace-provision.js → shared/workspace/session-provision.js} +15 -12
  174. package/dist/shared/workspace/session-provision.js.map +1 -0
  175. package/package.json +4 -4
  176. package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +110 -14
  177. package/src/__test-utils__/execution-record-fixture.ts +104 -0
  178. package/src/__test-utils__/harness-boot-order-child.ts +58 -0
  179. package/src/__test-utils__/harness-contract/contract.ts +128 -83
  180. package/src/__test-utils__/harness-contract/recording-sink.ts +15 -4
  181. package/src/__test-utils__/harness-contract/runtime-contract.ts +666 -0
  182. package/src/__test-utils__/harness-contract/scripted-adapter.ts +92 -32
  183. package/src/__test-utils__/harness-contract/types.ts +85 -9
  184. package/src/__test-utils__/hermetic-activity.ts +33 -8
  185. package/src/__test-utils__/model-registry-fixture.ts +72 -0
  186. package/src/__test-utils__/module-specifiers.ts +82 -0
  187. package/src/__test-utils__/turn-input-fixture.ts +155 -0
  188. package/src/__tests__/harness-boot-order.test.ts +77 -0
  189. package/src/__tests__/harness-contract.test.ts +7 -5
  190. package/src/__tests__/runner-manager.test.ts +18 -0
  191. package/src/activities/execute-cursor/__test-utils__/__tests__/scripted-double.test.ts +102 -0
  192. package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +396 -0
  193. package/src/activities/execute-cursor/__test-utils__/cursor-hook-harness.ts +66 -0
  194. package/src/activities/execute-cursor/__test-utils__/gateway-substrate.ts +2 -43
  195. package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +65 -145
  196. package/src/activities/execute-cursor/__test-utils__/scripted-agent.ts +30 -4
  197. package/src/activities/execute-cursor/__test-utils__/scripted-sdk.ts +96 -8
  198. package/src/activities/execute-cursor/__tests__/adapter-is-temporal-free.test.ts +45 -0
  199. package/src/activities/execute-cursor/__tests__/approval-decisions-agree.test.ts +90 -0
  200. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +7 -8
  201. package/src/activities/execute-cursor/__tests__/capture-flow.test.ts +28 -1
  202. package/src/activities/execute-cursor/__tests__/deny-gate-exact-apply.test.ts +1 -1
  203. package/src/activities/execute-cursor/__tests__/fetch-interceptor.test.ts +64 -6
  204. package/src/activities/execute-cursor/__tests__/hermetic/deny-and-retry.test.ts +1 -1
  205. package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +1 -1
  206. package/src/activities/execute-cursor/__tests__/hermetic/goldens/cost-cap.status.json +53 -0
  207. package/src/activities/execute-cursor/__tests__/hermetic/goldens/pause.status.json +1 -6
  208. package/src/activities/execute-cursor/__tests__/hermetic/goldens/platform-stop.status.json +56 -0
  209. package/src/activities/execute-cursor/__tests__/hermetic/goldens/recovery-transport-timeout.status.json +48 -0
  210. package/src/activities/execute-cursor/__tests__/hermetic/goldens/resolution-error.status.json +18 -0
  211. package/src/activities/execute-cursor/__tests__/hermetic/goldens/run-cancelled.status.json +36 -0
  212. package/src/activities/execute-cursor/__tests__/hermetic/goldens/run-error-non-retryable.status.json +37 -0
  213. package/src/activities/execute-cursor/__tests__/hermetic/goldens/sdk-error-at-create.status.json +38 -0
  214. package/src/activities/execute-cursor/__tests__/hermetic/goldens/stall.status.json +59 -0
  215. package/src/activities/execute-cursor/__tests__/hermetic/goldens/unattributed-hook-block.status.json +79 -0
  216. package/src/activities/execute-cursor/__tests__/hermetic/goldens/worker-shutdown.status.json +2 -7
  217. package/src/activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts +170 -0
  218. package/src/activities/execute-cursor/__tests__/hermetic/pause-vs-shutdown.test.ts +22 -18
  219. package/src/activities/execute-cursor/__tests__/hermetic/plain-turn.test.ts +1 -1
  220. package/src/activities/execute-cursor/__tests__/hermetic/recovery-fresh-agent.test.ts +1 -1
  221. package/src/activities/execute-cursor/__tests__/hermetic/run-wait-arms.test.ts +286 -0
  222. package/src/activities/execute-cursor/__tests__/hermetic/stream-self-stop-arms.test.ts +332 -0
  223. package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +193 -0
  224. package/src/activities/execute-cursor/__tests__/hermetic/tool-call.test.ts +1 -1
  225. package/src/activities/execute-cursor/__tests__/hermetic/unattributed-hook-block.test.ts +185 -0
  226. package/src/activities/execute-cursor/__tests__/hermetic/workspace-lock-timeout.test.ts +151 -0
  227. package/src/activities/execute-cursor/__tests__/http2-interceptor.test.ts +65 -35
  228. package/src/activities/execute-cursor/__tests__/message-translator.test.ts +0 -40
  229. package/src/activities/execute-cursor/__tests__/same-identity-reproposal.test.ts +171 -0
  230. package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +118 -243
  231. package/src/activities/execute-cursor/__tests__/usage-pricing.test.ts +84 -0
  232. package/src/activities/execute-cursor/adapter.ts +138 -0
  233. package/src/activities/execute-cursor/approval-state.ts +2 -2
  234. package/src/activities/execute-cursor/capture-flow.ts +18 -41
  235. package/src/activities/execute-cursor/cursor-capabilities.ts +35 -0
  236. package/src/activities/execute-cursor/cursor-mcp-config.ts +2 -2
  237. package/src/activities/execute-cursor/fetch-interceptor.ts +48 -45
  238. package/src/activities/execute-cursor/http2-interceptor.ts +47 -34
  239. package/src/activities/execute-cursor/message-translator.ts +90 -45
  240. package/src/activities/execute-cursor/prompt-builder.ts +327 -12
  241. package/src/activities/execute-cursor/rejection-capture.ts +5 -12
  242. package/src/activities/execute-cursor/session-lifecycle.ts +1 -5
  243. package/src/activities/execute-cursor/turn-boundary.ts +1 -1
  244. package/src/activities/execute-cursor/turn-settle.ts +601 -0
  245. package/src/activities/execute-cursor/turn-setup.ts +645 -0
  246. package/src/activities/execute-cursor/turn-stream.ts +84 -210
  247. package/src/activities/execute-cursor/turn.ts +240 -0
  248. package/src/activities/execute-cursor/usage-pricing.ts +67 -0
  249. package/src/activities/execute-deep-agent/approval-file-change.ts +1 -1
  250. package/src/activities/execute-deep-agent/environment.ts +1 -1
  251. package/src/activities/execute-deep-agent/setup.ts +3 -2
  252. package/src/activities/hydrate-workflow-execution.ts +1 -1
  253. package/src/config.ts +13 -0
  254. package/src/harness/__tests__/import-direction.test.ts +168 -0
  255. package/src/harness/__tests__/persist-chokepoint.test.ts +146 -0
  256. package/src/harness/__tests__/registry.test.ts +1 -0
  257. package/src/harness/__tests__/run-turn.test.ts +165 -0
  258. package/src/harness/__tests__/stop-controller.test.ts +49 -0
  259. package/src/harness/__tests__/turn-context.test.ts +178 -0
  260. package/src/harness/__tests__/usage-accumulator.test.ts +83 -0
  261. package/src/harness/capabilities.ts +17 -0
  262. package/src/harness/persist-chokepoint.ts +112 -0
  263. package/src/harness/registry.ts +79 -5
  264. package/src/harness/run-turn.ts +618 -0
  265. package/src/harness/stop-controller.ts +83 -0
  266. package/src/harness/terminal-table.ts +276 -0
  267. package/src/harness/turn-context.ts +1028 -0
  268. package/src/harness/types.ts +248 -53
  269. package/src/harness/usage-accumulator.ts +122 -0
  270. package/src/harness-adapters.ts +30 -0
  271. package/src/main.ts +1 -1
  272. package/src/runner-manager.ts +68 -61
  273. package/src/runner.ts +67 -78
  274. package/src/shared/__tests__/attachment-naming.test.ts +1 -1
  275. package/src/{activities/execute-cursor → shared}/__tests__/attachment-resolver.test.ts +6 -4
  276. package/src/{activities/execute-cursor → shared}/__tests__/cost-guard.test.ts +2 -1
  277. package/src/{activities/execute-cursor → shared}/__tests__/exact-apply.test.ts +3 -3
  278. package/src/{activities/execute-cursor → shared}/__tests__/extract-structured-output.test.ts +8 -8
  279. package/src/{activities/execute-cursor → shared}/__tests__/persist-decision.test.ts +4 -2
  280. package/src/{activities/execute-cursor → shared}/__tests__/skill-resolver.test.ts +1 -1
  281. package/src/shared/__tests__/subagent-rows.test.ts +34 -0
  282. package/src/shared/__tests__/worker-shutdown.test.ts +44 -39
  283. package/src/shared/approval-policy.ts +1 -1
  284. package/src/{activities/execute-cursor → shared}/attachment-resolver.ts +6 -6
  285. package/src/{activities/execute-cursor → shared}/blueprint-resolver.ts +7 -78
  286. package/src/shared/channel-attachment.ts +1 -1
  287. package/src/{activities/execute-cursor → shared}/cost-guard.ts +5 -1
  288. package/src/{activities/execute-cursor → shared}/env-resolver.ts +1 -1
  289. package/src/{activities/execute-cursor → shared}/exact-apply.ts +7 -7
  290. package/src/shared/execution-context.ts +45 -0
  291. package/src/{activities/execute-cursor → shared}/extract-structured-output.ts +10 -7
  292. package/src/shared/filereview/capture.ts +1 -1
  293. package/src/shared/heartbeat.ts +13 -33
  294. package/src/{activities/execute-cursor → shared}/persist-decision.ts +5 -2
  295. package/src/{activities/execute-cursor → shared}/skill-resolver.ts +20 -6
  296. package/src/shared/subagent-rows.ts +39 -0
  297. package/src/shared/worker-shutdown.ts +55 -25
  298. package/src/{activities/execute-cursor/__tests__/workspace-provision.test.ts → shared/workspace/__tests__/session-provision.test.ts} +25 -28
  299. package/src/shared/workspace/platform-dir.ts +1 -1
  300. package/src/{activities/execute-cursor/workspace-provision.ts → shared/workspace/session-provision.ts} +29 -16
  301. package/dist/activities/execute-cursor/attachment-resolver.js.map +0 -1
  302. package/dist/activities/execute-cursor/blueprint-resolver.js.map +0 -1
  303. package/dist/activities/execute-cursor/cost-guard.js.map +0 -1
  304. package/dist/activities/execute-cursor/env-resolver.js.map +0 -1
  305. package/dist/activities/execute-cursor/exact-apply.js.map +0 -1
  306. package/dist/activities/execute-cursor/extract-structured-output.js.map +0 -1
  307. package/dist/activities/execute-cursor/index.d.ts +0 -209
  308. package/dist/activities/execute-cursor/index.js +0 -2345
  309. package/dist/activities/execute-cursor/index.js.map +0 -1
  310. package/dist/activities/execute-cursor/persist-decision.js.map +0 -1
  311. package/dist/activities/execute-cursor/skill-resolver.js.map +0 -1
  312. package/dist/activities/execute-cursor/usage-accumulator.d.ts +0 -89
  313. package/dist/activities/execute-cursor/usage-accumulator.js +0 -121
  314. package/dist/activities/execute-cursor/usage-accumulator.js.map +0 -1
  315. package/dist/activities/execute-cursor/workspace-provision.d.ts +0 -42
  316. package/dist/activities/execute-cursor/workspace-provision.js.map +0 -1
  317. package/src/activities/execute-cursor/__tests__/usage-accumulator.test.ts +0 -164
  318. package/src/activities/execute-cursor/index.ts +0 -2876
  319. package/src/activities/execute-cursor/usage-accumulator.ts +0 -169
  320. /package/dist/{activities/execute-cursor → shared}/env-resolver.js +0 -0
@@ -1,38 +1,38 @@
1
1
  /**
2
2
  * The Cursor harness's stream phase — the single per-event consumption loop that
3
3
  * turns a live Cursor SDK run into the streamed transcript, mid-run progress, and
4
- * the flags that decide how the turn ends.
4
+ * the one flag that decides how the turn goes on (the first-denial stop).
5
5
  *
6
- * Extracted from the activity entry point (index.ts) so that BOTH the primary
7
- * turn and the two recovery retries (poisoned-handle / transport-timeout) drive
8
- * the exact same code. The retries previously re-implemented a stripped "bare"
6
+ * Extracted from the activity entry point so that BOTH the primary turn and
7
+ * the two recovery retries (poisoned-handle / transport-timeout) drive the
8
+ * exact same code. The retries previously re-implemented a stripped "bare"
9
9
  * loop that dropped live persist, DD-32/DD-33 mid-run progress, sub-agent
10
- * tracking, the first-denial early stop, and correct pause/stall handling — so a
10
+ * tracking, the first-denial early stop, and correct pause handling — so a
11
11
  * retry froze the UI and mis-handled a mid-retry pause. One loop removes that
12
12
  * drift by construction.
13
13
  *
14
- * This mirrors the deep-agent harness's `streamExecution` seam
15
- * (execute-deep-agent/streaming.ts): injected `heartbeat`/`isCancelled` so it
16
- * runs without Temporal, a structural `StreamableRun` so it runs without the live
17
- * SDK, and a result (the terminal reason) instead of internal terminal mapping.
18
- * The one deliberate difference: this consumer REPORTS why the stream ended and
19
- * leaves the terminal MAPPING to the activity, because Cursor's mapping is
20
- * entangled with worker-shutdown-vs-pause disambiguation, the turn boundary,
21
- * structured output, and recovery retries all of which must stay in index.ts.
14
+ * What the loop asks of the runtime, through the sink (`harness/types.ts`):
15
+ * `recordActivity()` per event (with the tool name) and per delta, so the
16
+ * runtime's stall watchdog measures the engine; `reportUsage()` per
17
+ * `turn-ended` delta, priced here at the requested variant's rates
18
+ * (`usage-pricing.ts`), so the runtime accounts and enforces the cost cap;
19
+ * `requestPersist()` where a discrete change or the streaming cadence says
20
+ * so (`shared/persist-decision.ts` over this loop's own dirty flags), AWAITED,
21
+ * so a platform STOP the runtime reads from that write aborts the signal
22
+ * before the next event is pulled; and `stopSignal`, checked at every event
23
+ * boundary and listened to inside the pull, where an abort cancels the SDK
24
+ * run — the one way a wedged stream is unblocked, and the same act for every
25
+ * cause of stopping (the runtime knows why; this loop never does).
26
+ *
27
+ * Until S2 M3 this loop armed its own stall watchdog, enforced the cost cap,
28
+ * read STOP from its own persist, and told a pause from the activity's
29
+ * cancellation signal; every one of those is the runtime's now, and the loop
30
+ * reports only `completed`, `first-denial` or `interrupted`.
22
31
  */
23
32
 
24
- import { create } from "@bufbuild/protobuf";
25
- import { CancelledFailure } from "@temporalio/activity";
26
- import type { AgentExecutionStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
27
- import { ExecutionControlSignal } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
28
- import { StreamingUsageSummarySchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/usage_pb";
29
33
  import type { SDKMessage, InteractionUpdate } from "@cursor/sdk";
30
- import {
31
- startStallWatchdog,
32
- StallTimeoutError,
33
- type StallWatchdog,
34
- } from "../../shared/stall-watchdog.js";
35
- import { shouldPersistStreamingStatus } from "./persist-decision.js";
34
+ import type { TurnSink } from "../../harness/types.js";
35
+ import { shouldPersistStreamingStatus } from "../../shared/persist-decision.js";
36
36
  import { approvalDenials, readDenialLedger } from "./approval-state.js";
37
37
  import {
38
38
  captureFileChangeProgress,
@@ -43,9 +43,8 @@ import type { MessageAccumulator } from "./message-translator.js";
43
43
  import type { DeltaEnricher } from "./delta-enricher.js";
44
44
  import type { TodoTracker } from "./todo-tracker.js";
45
45
  import type { StreamingUpdateScheduler } from "../../shared/streaming-scheduler.js";
46
- import type { UsageAccumulator } from "./usage-accumulator.js";
46
+ import type { CursorUsagePricer } from "./usage-pricing.js";
47
47
  import type { createCursorEventRecorder } from "./cursor-event-recorder.js";
48
- import { costCapExceeded } from "./cost-guard.js";
49
48
 
50
49
  /**
51
50
  * The subset of the Cursor SDK `Run` the stream phase consumes. Kept structural
@@ -60,101 +59,60 @@ export interface StreamableRun {
60
59
  export type CursorTurnEventRecorder = ReturnType<typeof createCursorEventRecorder>;
61
60
 
62
61
  /**
63
- * Why the turn's stream ended. The activity maps each reason to a terminal
64
- * outcome (see resolvePreBoundaryTerminal in index.ts): `completed` and
65
- * `first-denial` proceed to the turn boundary; the rest are pre-boundary
66
- * terminals that return or throw.
62
+ * Why the turn's stream ended. `completed` and `first-denial` proceed to the
63
+ * turn boundary; `interrupted` is the runtime's stop, and the adapter settles
64
+ * `interrupted` (the runtime classifies the cause from its own evidence).
67
65
  */
68
- export type TurnStreamReason =
69
- | "completed"
70
- | "paused"
71
- | "stalled"
72
- | "first-denial"
73
- | "platform-stop"
74
- | "cost-cap";
66
+ export type TurnStreamReason = "completed" | "first-denial" | "interrupted";
75
67
 
76
68
  /**
77
- * Single owner for every flag the turn's stream produces. Before this, these
78
- * eleven fields lived as scattered `let`s co-written by FOUR concurrent
79
- * producers the SDK `onDelta`, the fs denial-watcher, the stall-watchdog, and
80
- * the loop the classic "who writes this field?" hazard. Consolidating them into
81
- * one object (created once per turn, shared by every producer, the epilogue, and
82
- * the outer catch/finally) makes ownership explicit and lets the primary turn and
83
- * both recovery retries drive the identical stream code.
84
- *
85
- * Field ownership is annotated per field: exactly one primary writer, plus any
86
- * documented producer/consumer handshakes.
69
+ * The flags the turn's stream produces that outlive the loop: created once per
70
+ * turn and shared by the primary stream, both recovery retries, the boundary
71
+ * and the settle, so every reader sees ONE source of truth. Field ownership
72
+ * is annotated per field: exactly one primary writer.
87
73
  */
88
74
  export interface TurnStreamState {
89
- /** Written by: onDelta (heartbeat cancel) + the loop's cancellation check. Read by: the loop, epilogue, outer catch. */
90
- pauseDetected: boolean;
91
- /** Written by: the stall-watchdog callback. Read by: the loop + epilogue. */
92
- stallDetected: boolean;
93
- stallError: StallTimeoutError | undefined;
94
- /** Written by: the loop (on the first ledger entry). Read by: the loop, epilogue, settleRetryTurn. */
75
+ /** Written by: the loop (on the first ledger entry). Read by: the loop, the boundary, settleRetryTurn. */
95
76
  firstDenialDetected: boolean;
96
77
  /** Written by: the fs denial-watcher (→ true) + the loop (→ false after a read). Read by: the loop. */
97
78
  denialLedgerDirty: boolean;
98
79
  /** Written by: the loop (the first-denial run.cancel()). Read by: the turn boundary. */
99
80
  denialCancelSettled: Promise<void> | undefined;
100
- /** Written by: the loop (a platform STOP signal from persist). Read by: the loop + epilogue. */
101
- platformStopSignaled: boolean;
102
- /** Written by: onDelta (a turn-ended usage delta pushed the estimate past max_cost_usd). Read by: the loop (cancel + break) + epilogue. */
103
- costCapExceeded: boolean;
104
81
  /** Written by: the loop (a stream ERROR status event) + the retry setup (reset). Read by: error classification. */
105
82
  streamErrorMessage: string | undefined;
106
- /** Written by: the loop (each tool_call). Read by: the stall-watchdog (message enrichment). */
107
- lastToolName: string | undefined;
108
83
  /** Written by: the loop. Read by: the event recorder, the persist cadence, and logs. */
109
84
  eventCount: number;
110
85
  /** Written + read by: onDelta (log the first turn's context attribution exactly once). */
111
86
  firstTurnAttributionLogged: boolean;
112
- /** The stall watchdog for the CURRENT stream, armed by consumeCursorTurnStream; held so onDelta can reset it and the activity's finally can stop it. */
113
- stallWatchdog: StallWatchdog | undefined;
114
87
  }
115
88
 
116
89
  export function newTurnStreamState(): TurnStreamState {
117
90
  return {
118
- pauseDetected: false,
119
- stallDetected: false,
120
- stallError: undefined,
121
91
  firstDenialDetected: false,
122
92
  denialLedgerDirty: false,
123
93
  denialCancelSettled: undefined,
124
- platformStopSignaled: false,
125
- costCapExceeded: false,
126
94
  streamErrorMessage: undefined,
127
- lastToolName: undefined,
128
95
  eventCount: 0,
129
96
  firstTurnAttributionLogged: false,
130
- stallWatchdog: undefined,
131
97
  };
132
98
  }
133
99
 
134
100
  /**
135
101
  * The subset of collaborators the shared onDelta needs. Broken out from
136
102
  * CursorTurnStreamDeps because the primary send happens BEFORE the accumulator
137
- * exists — onDelta only touches usage, the enricher, the heartbeat, and state.
103
+ * exists — onDelta only touches the sink, the pricer, the enricher, and state.
138
104
  */
139
105
  export interface TurnOnDeltaDeps {
140
- readonly usageAccumulator: UsageAccumulator;
106
+ readonly sink: TurnSink;
107
+ /** This harness's pricing of a `turn-ended` delta at the requested variant's rates. */
108
+ readonly usagePricer: CursorUsagePricer;
141
109
  readonly deltaEnricher: DeltaEnricher;
142
- /** Temporal heartbeat. Injected so the callback is testable without Temporal. */
143
- readonly heartbeat: () => void;
144
110
  readonly promptEstimatedTokens: number;
145
111
  readonly executionId: string;
146
112
  readonly state: TurnStreamState;
147
- /**
148
- * ExecutionConfig.max_cost_usd — 0/unset disables the cap. Checked by
149
- * onDelta after each turn-ended usage delta lands (the only point the
150
- * running estimate advances); the loop performs the actual run.cancel().
151
- * See cost-guard.ts for the semantics.
152
- */
153
- readonly maxCostUsd: number;
154
113
  }
155
114
 
156
115
  export interface CursorTurnStreamDeps extends TurnOnDeltaDeps {
157
- readonly status: AgentExecutionStatus;
158
116
  readonly accumulator: MessageAccumulator;
159
117
  readonly todoTracker: TodoTracker;
160
118
  readonly eventRecorder: CursorTurnEventRecorder | undefined;
@@ -164,46 +122,27 @@ export interface CursorTurnStreamDeps extends TurnOnDeltaDeps {
164
122
  readonly changeSetId: string;
165
123
  /** Session HITL dir holding the denial ledger; undefined → no gate installed → no first-denial stop. */
166
124
  readonly hitlDir: string | undefined;
167
- readonly stallTimeoutMs: number;
168
- /** The single size-bounded persist chokepoint. Returns the platform control signal. */
169
- readonly persist: (status: AgentExecutionStatus) => Promise<ExecutionControlSignal>;
170
- /** Temporal cancellation check. Injected so the loop is testable without Temporal. */
171
- readonly isCancelled: () => boolean;
172
125
  }
173
126
 
174
127
  /**
175
128
  * Build the shared onDelta callback. The Cursor SDK's fine-grained delta channel
176
129
  * carries token usage, live shell output, and precise tool-call timings; it also
177
- * fires far more often than discrete stream events, so it is where the stall
178
- * timer is reset during a long model generation. A heartbeat CancelledFailure
179
- * here flags the pause so the loop and epilogue treat it as a user pause (the
180
- * bare retry loops swallowed this — the cause of the mid-retry mislabel).
130
+ * fires far more often than discrete stream events, so it is where the runtime's
131
+ * stall timer is reset during a long model generation.
181
132
  */
182
133
  export function makeCursorTurnOnDelta(
183
134
  deps: TurnOnDeltaDeps,
184
135
  ): (event: { update: InteractionUpdate }) => void {
185
- const { usageAccumulator, deltaEnricher, heartbeat, promptEstimatedTokens, executionId, state, maxCostUsd } =
186
- deps;
136
+ const { sink, usagePricer, deltaEnricher, promptEstimatedTokens, executionId, state } = deps;
187
137
  return ({ update }) => {
188
- // Reset the stall timer on the delta channel too: a long model generation
189
- // emits token deltas but few discrete stream events, so resetting only in the
190
- // stream loop would false-positive a stall.
191
- state.stallWatchdog?.recordActivity();
138
+ // Progress on the delta channel too: a long model generation emits token
139
+ // deltas but few discrete stream events, and resetting only in the stream
140
+ // loop would false-positive a stall.
141
+ sink.recordActivity();
192
142
  if (update.type === "turn-ended" && update.usage) {
193
- usageAccumulator.addTurn(update.usage);
194
-
195
- // max_cost_usd enforcement (cost-guard.ts): the running estimate only
196
- // advances here, so this is the single check point. onDelta cannot reach
197
- // the run — the loop reads the flag and performs the clean cancel.
198
- if (!state.costCapExceeded
199
- && costCapExceeded(maxCostUsd, usageAccumulator.snapshot().estimatedCostUsd)) {
200
- state.costCapExceeded = true;
201
- console.warn(
202
- `ExecuteCursor cost cap exceeded: execution=${executionId}, ` +
203
- `estimatedCostUsd=${usageAccumulator.snapshot().estimatedCostUsd.toFixed(4)}, ` +
204
- `maxCostUsd=${maxCostUsd.toFixed(2)}`,
205
- );
206
- }
143
+ // The running estimate advances only here; the runtime enforces the cap
144
+ // and aborts the signal, which the loop reads at the next boundary.
145
+ sink.reportUsage(usagePricer.price(update.usage));
207
146
 
208
147
  if (!state.firstTurnAttributionLogged) {
209
148
  state.firstTurnAttributionLogged = true;
@@ -217,15 +156,6 @@ export function makeCursorTurnOnDelta(
217
156
  }
218
157
  }
219
158
  deltaEnricher.processDelta(update);
220
- try {
221
- heartbeat();
222
- } catch (hbErr) {
223
- if (hbErr instanceof CancelledFailure) {
224
- state.pauseDetected = true;
225
- return;
226
- }
227
- throw hbErr;
228
- }
229
159
  };
230
160
  }
231
161
 
@@ -234,94 +164,58 @@ export function makeCursorTurnOnDelta(
234
164
  * transcript, todos, sub-agent tracking, live persist, and DD-32/DD-33 mid-run
235
165
  * progress, and reporting WHY the stream ended.
236
166
  *
237
- * Arms + stops its own stall watchdog (stored on `state.stallWatchdog` so the
238
- * shared onDelta can reset it and the activity's finally can stop it as a
239
- * backstop). Mutates `deps.status` + `deps.state` in place. The caller owns the
240
- * post-stream finalize and the terminal mapping.
167
+ * Mutates `deps.sink.status` + `deps.state` in place. The caller owns the
168
+ * post-stream finalize and the settle.
241
169
  */
242
170
  export async function consumeCursorTurnStream(
243
171
  run: StreamableRun,
244
172
  deps: CursorTurnStreamDeps,
245
173
  ): Promise<TurnStreamReason> {
246
174
  const {
247
- status,
175
+ sink,
248
176
  accumulator,
249
177
  todoTracker,
250
178
  deltaEnricher,
251
179
  eventRecorder,
252
180
  scheduler,
253
- usageAccumulator,
254
181
  progressSubstrate,
255
182
  progressState,
256
183
  changeSetId,
257
184
  hitlDir,
258
185
  executionId,
259
- stallTimeoutMs,
260
- persist,
261
- heartbeat,
262
- isCancelled,
263
186
  state,
264
187
  } = deps;
188
+ const { status, stopSignal } = sink;
265
189
 
266
- // Arm the stall watchdog now that the run exists. The activity's periodic
267
- // heartbeat proves the process is alive, not that the agent is progressing: if
268
- // the stream wedges (a tool call or model connection that never returns), no
269
- // event/delta arrives and the turn would hang forever. On stall we end the run
270
- // cleanly via the SDK's run.cancel() (guarded by supports("cancel")), which
271
- // unblocks the for-await; the caller then reports EXECUTION_FAILED with a
272
- // recognizable, actionable message.
273
- state.stallWatchdog = startStallWatchdog(stallTimeoutMs, (idleMs) => {
274
- state.stallDetected = true;
275
- state.stallError = new StallTimeoutError(
276
- idleMs,
277
- state.lastToolName ? `last tool: ${state.lastToolName}` : undefined,
278
- );
279
- console.warn(
280
- `ExecuteCursor stall detected: execution=${executionId}, idleMs=${idleMs}, lastTool=${state.lastToolName ?? "none"}`,
281
- );
190
+ // The runtime's stop, whatever its cause, ends the run through the SDK's
191
+ // own cancel: that is what unblocks a wedged `for await` (a stall), and it
192
+ // stops the engine's tools and deltas from outliving the turn on every
193
+ // other cause too. Guarded by supports("cancel") as the loop's own cancels
194
+ // are; the teardown rejection it can cause is swallowed below.
195
+ const cancelOnStop = (): void => {
196
+ console.log(`ExecuteCursor stopping stream on the runtime's stop signal: execution=${executionId}`);
282
197
  if (run.supports?.("cancel")) {
283
198
  void run.cancel().catch((cancelErr) => {
284
199
  console.warn(
285
- `ExecuteCursor run.cancel() after stall failed (non-fatal): execution=${executionId}, ` +
200
+ `ExecuteCursor run.cancel() after stop failed (non-fatal): execution=${executionId}, ` +
286
201
  `error=${cancelErr instanceof Error ? cancelErr.message : cancelErr}`,
287
202
  );
288
203
  });
289
204
  }
290
- });
205
+ };
206
+ if (stopSignal.aborted) {
207
+ cancelOnStop();
208
+ return "interrupted";
209
+ }
210
+ stopSignal.addEventListener("abort", cancelOnStop, { once: true });
291
211
 
292
212
  try {
293
213
  for await (const event of run.stream()) {
294
- if (state.pauseDetected || isCancelled()) {
295
- state.pauseDetected = true;
296
- break;
297
- }
298
- if (state.stallDetected) break;
214
+ if (stopSignal.aborted) break;
299
215
 
300
- // Cost cap (cost-guard.ts): onDelta flagged the overrun on a turn-ended
301
- // usage delta; end the run through the same clean-cancel pattern as the
302
- // stall watchdog and the first-denial stop. Fire-and-forget is correct
303
- // here — nothing downstream waits on this turn's agent (unlike the
304
- // first-denial stop, whose ledger read needs a stopped agent).
305
- if (state.costCapExceeded) {
306
- console.log(
307
- `ExecuteCursor stopping stream at cost cap: execution=${executionId}`,
308
- );
309
- if (run.supports?.("cancel")) {
310
- void run.cancel().catch((cancelErr) => {
311
- console.warn(
312
- `ExecuteCursor run.cancel() after cost cap failed (non-fatal): execution=${executionId}, ` +
313
- `error=${cancelErr instanceof Error ? cancelErr.message : cancelErr}`,
314
- );
315
- });
316
- }
317
- break;
318
- }
319
-
320
- // Progress: reset the stall timer on every stream event.
321
- state.stallWatchdog.recordActivity();
322
- if (event.type === "tool_call" && typeof event.name === "string") {
323
- state.lastToolName = event.name;
324
- }
216
+ // Progress: reset the runtime's stall timer on every stream event,
217
+ // naming the tool so a stall's copy can say `last tool: shell`.
218
+ sink.recordActivity(event.type === "tool_call" && typeof event.name === "string" ? event.name : undefined);
325
219
 
326
220
  eventRecorder?.record(event, state.eventCount);
327
221
 
@@ -405,9 +299,6 @@ export async function consumeCursorTurnStream(
405
299
  scheduler,
406
300
  state.eventCount,
407
301
  );
408
- if (usageAccumulator.hasTurns) {
409
- status.streamingUsage = create(StreamingUsageSummarySchema, usageAccumulator.snapshot());
410
- }
411
302
  if (shouldPersist) {
412
303
  // Sync sub-agent executions into status before every persist so the live
413
304
  // UI reflects delegation (including the IN_PROGRESS state) while the
@@ -425,52 +316,35 @@ export async function consumeCursorTurnStream(
425
316
  state: progressState,
426
317
  });
427
318
  }
428
- const signal = await persist(status);
319
+ // Awaited: the runtime reads the control plane's answer to this write,
320
+ // and a STOP must be seen at the next event boundary, not one event late.
321
+ await sink.requestPersist();
429
322
  deltaEnricher.markPersisted();
430
323
  todoTracker.markPersisted();
431
324
  accumulator.markPersisted();
432
325
  scheduler.markUpdateSent(state.eventCount);
433
- heartbeat();
434
- if (signal === ExecutionControlSignal.STOP) {
435
- state.platformStopSignaled = true;
436
- console.warn(`ExecuteCursor platform stop signal received: execution=${executionId}`);
437
- }
438
- }
439
-
440
- if (state.platformStopSignaled) {
441
- console.log(
442
- `ExecuteCursor stopping stream due to platform stop signal: execution=${executionId}`,
443
- );
444
- break;
445
326
  }
446
327
  }
447
328
  } catch (streamErr) {
448
- // run.cancel() — from the stall watchdog, the first-denial stop, or the
449
- // cost-cap stop — can make the stream iterator reject as it tears down;
450
- // that is the expected teardown for all three, so swallow it and fall
451
- // through. Anything else is a genuine stream failure — rethrow it to the
452
- // activity's error handler.
453
- if (!state.stallDetected && !state.firstDenialDetected && !state.costCapExceeded) {
329
+ // run.cancel() — from the runtime's stop or the first-denial stop can
330
+ // make the stream iterator reject as it tears down; that is the expected
331
+ // teardown for both, so swallow it and fall through. Anything else is a
332
+ // genuine stream failure — rethrow it to the adapter's error handler.
333
+ if (!stopSignal.aborted && !state.firstDenialDetected) {
454
334
  throw streamErr;
455
335
  }
456
336
  console.warn(
457
337
  `ExecuteCursor stream ended via cancel: execution=${executionId}, ` +
458
- `stall=${state.stallDetected}, firstDenial=${state.firstDenialDetected}, ` +
459
- `costCap=${state.costCapExceeded}`,
338
+ `stopped=${stopSignal.aborted}, firstDenial=${state.firstDenialDetected}`,
460
339
  );
461
340
  } finally {
462
- state.stallWatchdog.stop();
341
+ stopSignal.removeEventListener("abort", cancelOnStop);
463
342
  }
464
343
 
465
- // Report why the stream ended, in the same precedence the activity's epilogue
466
- // applies: a stall (an EXECUTION_FAILED terminal) outranks everything; a
467
- // platform stop, a cost-cap stop, and a first denial are distinct
468
- // return/proceed outcomes; a pause is the fallback for a cancellation with
469
- // no other cause.
470
- if (state.stallDetected) return "stalled";
471
- if (state.platformStopSignaled) return "platform-stop";
472
- if (state.costCapExceeded) return "cost-cap";
344
+ // Report why the stream ended: the runtime's stop outranks a first denial
345
+ // (there is no review to open on a stopped turn), a first denial outranks a
346
+ // natural end.
347
+ if (stopSignal.aborted) return "interrupted";
473
348
  if (state.firstDenialDetected) return "first-denial";
474
- if (state.pauseDetected || isCancelled()) return "paused";
475
349
  return "completed";
476
350
  }