@stigmer/runner 3.15.3-dev.20260914121148 → 3.16.0

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 (592) hide show
  1. package/README.md +2 -1
  2. package/dist/.build-fingerprint +1 -1
  3. package/dist/__test-utils__/approval-contract/types.d.ts +1 -1
  4. package/dist/__test-utils__/hermetic-activity.d.ts +61 -7
  5. package/dist/__test-utils__/hermetic-activity.js +100 -9
  6. package/dist/__test-utils__/hermetic-activity.js.map +1 -1
  7. package/dist/__test-utils__/model-registry-fixture.d.ts +22 -3
  8. package/dist/__test-utils__/model-registry-fixture.js +22 -7
  9. package/dist/__test-utils__/model-registry-fixture.js.map +1 -1
  10. package/dist/activities/execute-cursor/__test-utils__/contract-subject.d.ts +2 -2
  11. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js +2 -2
  12. package/dist/activities/execute-cursor/__test-utils__/fold.d.ts +61 -0
  13. package/dist/activities/execute-cursor/__test-utils__/fold.js +94 -0
  14. package/dist/activities/execute-cursor/__test-utils__/fold.js.map +1 -0
  15. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js +1 -1
  16. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js.map +1 -1
  17. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +47 -12
  18. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +41 -10
  19. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
  20. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.d.ts +15 -6
  21. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js +17 -4
  22. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js.map +1 -1
  23. package/dist/activities/execute-cursor/adapter.d.ts +4 -4
  24. package/dist/activities/execute-cursor/adapter.js +4 -4
  25. package/dist/activities/execute-cursor/approval-policy.d.ts +10 -10
  26. package/dist/activities/execute-cursor/approval-policy.js +12 -23
  27. package/dist/activities/execute-cursor/approval-policy.js.map +1 -1
  28. package/dist/activities/execute-cursor/approval-state.d.ts +35 -1
  29. package/dist/activities/execute-cursor/approval-state.js +65 -0
  30. package/dist/activities/execute-cursor/approval-state.js.map +1 -1
  31. package/dist/activities/execute-cursor/{message-translator.d.ts → boundary-rows.d.ts} +45 -341
  32. package/dist/activities/execute-cursor/boundary-rows.js +1018 -0
  33. package/dist/activities/execute-cursor/boundary-rows.js.map +1 -0
  34. package/dist/activities/execute-cursor/cursor-capabilities.d.ts +1 -1
  35. package/dist/activities/execute-cursor/cursor-capabilities.js +1 -1
  36. package/dist/activities/execute-cursor/cursor-event-recorder.d.ts +33 -14
  37. package/dist/activities/execute-cursor/cursor-event-recorder.js +43 -21
  38. package/dist/activities/execute-cursor/cursor-event-recorder.js.map +1 -1
  39. package/dist/activities/execute-cursor/prompt-builder.d.ts +3 -3
  40. package/dist/activities/execute-cursor/prompt-builder.js +4 -4
  41. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  42. package/dist/activities/execute-cursor/service-tier.js +1 -2
  43. package/dist/activities/execute-cursor/service-tier.js.map +1 -1
  44. package/dist/activities/execute-cursor/sub-agent-steps.d.ts +79 -0
  45. package/dist/activities/execute-cursor/sub-agent-steps.js +180 -0
  46. package/dist/activities/execute-cursor/sub-agent-steps.js.map +1 -0
  47. package/dist/activities/execute-cursor/tool-result.d.ts +49 -0
  48. package/dist/activities/execute-cursor/tool-result.js +130 -0
  49. package/dist/activities/execute-cursor/tool-result.js.map +1 -0
  50. package/dist/activities/execute-cursor/translator.d.ts +178 -0
  51. package/dist/activities/execute-cursor/translator.js +485 -0
  52. package/dist/activities/execute-cursor/translator.js.map +1 -0
  53. package/dist/activities/execute-cursor/turn-boundary.d.ts +15 -5
  54. package/dist/activities/execute-cursor/turn-boundary.js +10 -14
  55. package/dist/activities/execute-cursor/turn-boundary.js.map +1 -1
  56. package/dist/activities/execute-cursor/turn-settle.d.ts +11 -7
  57. package/dist/activities/execute-cursor/turn-settle.js +47 -34
  58. package/dist/activities/execute-cursor/turn-settle.js.map +1 -1
  59. package/dist/activities/execute-cursor/turn-setup.d.ts +2 -2
  60. package/dist/activities/execute-cursor/turn-setup.js +5 -5
  61. package/dist/activities/execute-cursor/turn-setup.js.map +1 -1
  62. package/dist/activities/execute-cursor/turn-stream.d.ts +23 -14
  63. package/dist/activities/execute-cursor/turn-stream.js +41 -28
  64. package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
  65. package/dist/activities/execute-cursor/turn.d.ts +4 -4
  66. package/dist/activities/execute-cursor/turn.js +5 -5
  67. package/dist/activities/execute-cursor/usage-pricing.d.ts +2 -2
  68. package/dist/activities/execute-cursor/usage-pricing.js +2 -2
  69. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.d.ts +2 -2
  70. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js +2 -2
  71. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.d.ts +16 -11
  72. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js +22 -10
  73. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js.map +1 -1
  74. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js +1 -1
  75. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js.map +1 -1
  76. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.d.ts +2 -3
  77. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js +2 -3
  78. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js.map +1 -1
  79. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.d.ts +12 -3
  80. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js +18 -4
  81. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js.map +1 -1
  82. package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.d.ts +10 -1
  83. package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.js +24 -11
  84. package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.js.map +1 -1
  85. package/dist/activities/execute-deep-agent/adapter.d.ts +1 -1
  86. package/dist/activities/execute-deep-agent/adapter.js +1 -1
  87. package/dist/activities/execute-deep-agent/approval-file-change.d.ts +19 -19
  88. package/dist/activities/execute-deep-agent/approval-file-change.js +16 -15
  89. package/dist/activities/execute-deep-agent/approval-file-change.js.map +1 -1
  90. package/dist/activities/execute-deep-agent/deep-agent-capabilities.d.ts +2 -2
  91. package/dist/activities/execute-deep-agent/deep-agent-capabilities.js +2 -2
  92. package/dist/activities/execute-deep-agent/hitl.d.ts +2 -2
  93. package/dist/activities/execute-deep-agent/hitl.js +2 -2
  94. package/dist/activities/execute-deep-agent/inline-publisher.d.ts +13 -3
  95. package/dist/activities/execute-deep-agent/inline-publisher.js +3 -3
  96. package/dist/activities/execute-deep-agent/inline-publisher.js.map +1 -1
  97. package/dist/activities/execute-deep-agent/prompt-builder.d.ts +3 -3
  98. package/dist/activities/execute-deep-agent/prompt-builder.js +6 -7
  99. package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
  100. package/dist/activities/execute-deep-agent/streaming-side-effects.d.ts +16 -8
  101. package/dist/activities/execute-deep-agent/streaming-side-effects.js +20 -33
  102. package/dist/activities/execute-deep-agent/streaming-side-effects.js.map +1 -1
  103. package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +3 -3
  104. package/dist/activities/execute-deep-agent/subagent-transformer.js +1 -1
  105. package/dist/activities/execute-deep-agent/translator.d.ts +134 -0
  106. package/dist/activities/execute-deep-agent/translator.js +418 -0
  107. package/dist/activities/execute-deep-agent/translator.js.map +1 -0
  108. package/dist/activities/execute-deep-agent/turn-settle.d.ts +13 -7
  109. package/dist/activities/execute-deep-agent/turn-settle.js +34 -45
  110. package/dist/activities/execute-deep-agent/turn-settle.js.map +1 -1
  111. package/dist/activities/execute-deep-agent/turn-setup.d.ts +8 -8
  112. package/dist/activities/execute-deep-agent/turn-setup.js +7 -7
  113. package/dist/activities/execute-deep-agent/turn-stream.d.ts +13 -10
  114. package/dist/activities/execute-deep-agent/turn-stream.js +44 -41
  115. package/dist/activities/execute-deep-agent/turn-stream.js.map +1 -1
  116. package/dist/activities/execute-deep-agent/turn.d.ts +3 -3
  117. package/dist/activities/execute-deep-agent/turn.js +3 -3
  118. package/dist/activities/generate-session-subject.d.ts +25 -4
  119. package/dist/activities/generate-session-subject.js +17 -7
  120. package/dist/activities/generate-session-subject.js.map +1 -1
  121. package/dist/client/stigmer-client.d.ts +17 -6
  122. package/dist/client/stigmer-client.js +47 -14
  123. package/dist/client/stigmer-client.js.map +1 -1
  124. package/dist/config.d.ts +6 -3
  125. package/dist/config.js +4 -1
  126. package/dist/config.js.map +1 -1
  127. package/dist/harness/approval-decisions.d.ts +1 -1
  128. package/dist/harness/approval-decisions.js +1 -1
  129. package/dist/harness/capabilities.d.ts +21 -11
  130. package/dist/harness/capabilities.js +2 -2
  131. package/dist/harness/capture.d.ts +4 -4
  132. package/dist/harness/capture.js +4 -4
  133. package/dist/harness/persist-chokepoint.d.ts +3 -3
  134. package/dist/harness/persist-chokepoint.js +3 -3
  135. package/dist/harness/registry.d.ts +2 -2
  136. package/dist/harness/registry.js +2 -2
  137. package/dist/harness/run-turn.d.ts +6 -4
  138. package/dist/harness/run-turn.js +31 -9
  139. package/dist/harness/run-turn.js.map +1 -1
  140. package/dist/harness/stop-controller.d.ts +1 -1
  141. package/dist/harness/stop-controller.js +1 -1
  142. package/dist/harness/terminal-table.d.ts +7 -7
  143. package/dist/harness/terminal-table.js +7 -7
  144. package/dist/harness/transcript/builder.d.ts +182 -0
  145. package/dist/harness/transcript/builder.js +693 -0
  146. package/dist/harness/transcript/builder.js.map +1 -0
  147. package/dist/harness/transcript/events.d.ts +218 -0
  148. package/dist/harness/transcript/events.js +50 -0
  149. package/dist/harness/transcript/events.js.map +1 -0
  150. package/dist/harness/transcript/state.d.ts +110 -0
  151. package/dist/harness/transcript/state.js +148 -0
  152. package/dist/harness/transcript/state.js.map +1 -0
  153. package/dist/harness/turn-context.d.ts +54 -38
  154. package/dist/harness/turn-context.js +42 -43
  155. package/dist/harness/turn-context.js.map +1 -1
  156. package/dist/harness/types.d.ts +63 -22
  157. package/dist/harness/types.js +12 -11
  158. package/dist/harness/types.js.map +1 -1
  159. package/dist/harness/usage-accumulator.d.ts +2 -2
  160. package/dist/harness/usage-accumulator.js +2 -2
  161. package/dist/harness-adapters.d.ts +5 -4
  162. package/dist/harness-adapters.js +5 -4
  163. package/dist/harness-adapters.js.map +1 -1
  164. package/dist/interceptors/run-credential-activity.d.ts +28 -0
  165. package/dist/interceptors/run-credential-activity.js +56 -0
  166. package/dist/interceptors/run-credential-activity.js.map +1 -0
  167. package/dist/middleware/approval-gate.d.ts +6 -0
  168. package/dist/middleware/approval-gate.js +7 -57
  169. package/dist/middleware/approval-gate.js.map +1 -1
  170. package/dist/middleware/cost-advisory.d.ts +3 -3
  171. package/dist/middleware/cost-advisory.js +3 -3
  172. package/dist/middleware/index.d.ts +1 -1
  173. package/dist/middleware/index.js +1 -1
  174. package/dist/runner-manager.js +10 -4
  175. package/dist/runner-manager.js.map +1 -1
  176. package/dist/shared/activity-input.d.ts +9 -0
  177. package/dist/shared/activity-input.js +17 -0
  178. package/dist/shared/activity-input.js.map +1 -1
  179. package/dist/shared/approval-policy.d.ts +53 -0
  180. package/dist/shared/approval-policy.js +76 -0
  181. package/dist/shared/approval-policy.js.map +1 -1
  182. package/dist/shared/args-preview.d.ts +45 -22
  183. package/dist/shared/args-preview.js +51 -41
  184. package/dist/shared/args-preview.js.map +1 -1
  185. package/dist/shared/attachment-resolver.d.ts +4 -4
  186. package/dist/shared/attachment-resolver.js +4 -4
  187. package/dist/shared/attachment-zip.d.ts +2 -2
  188. package/dist/shared/attachment-zip.js +2 -2
  189. package/dist/shared/channel-attachment.d.ts +8 -5
  190. package/dist/shared/channel-attachment.js +10 -6
  191. package/dist/shared/channel-attachment.js.map +1 -1
  192. package/dist/shared/cost-guard.d.ts +2 -2
  193. package/dist/shared/cost-guard.js +2 -2
  194. package/dist/shared/exact-apply.d.ts +1 -1
  195. package/dist/shared/exact-apply.js +1 -1
  196. package/dist/shared/execution-context.d.ts +2 -2
  197. package/dist/shared/execution-context.js +2 -2
  198. package/dist/shared/extract-structured-output.d.ts +2 -2
  199. package/dist/shared/extract-structured-output.js +2 -2
  200. package/dist/shared/filereview/cas-touched.d.ts +2 -2
  201. package/dist/shared/filereview/cas-touched.js +2 -2
  202. package/dist/shared/filereview/progress.d.ts +13 -0
  203. package/dist/shared/filereview/progress.js +13 -0
  204. package/dist/shared/filereview/progress.js.map +1 -1
  205. package/dist/shared/heartbeat.d.ts +1 -1
  206. package/dist/shared/heartbeat.js +1 -1
  207. package/dist/shared/llm-backend.d.ts +0 -4
  208. package/dist/shared/llm-backend.js +0 -4
  209. package/dist/shared/llm-backend.js.map +1 -1
  210. package/dist/shared/memory-attachment.d.ts +16 -9
  211. package/dist/shared/memory-attachment.js +18 -10
  212. package/dist/shared/memory-attachment.js.map +1 -1
  213. package/dist/shared/model-error.d.ts +1 -2
  214. package/dist/shared/model-error.js +1 -2
  215. package/dist/shared/model-error.js.map +1 -1
  216. package/dist/shared/persist-decision.d.ts +18 -24
  217. package/dist/shared/persist-decision.js +19 -11
  218. package/dist/shared/persist-decision.js.map +1 -1
  219. package/dist/shared/prompt-sections.d.ts +4 -4
  220. package/dist/shared/prompt-sections.js +4 -4
  221. package/dist/shared/run-credential-store.d.ts +32 -0
  222. package/dist/shared/run-credential-store.js +39 -0
  223. package/dist/shared/run-credential-store.js.map +1 -0
  224. package/dist/shared/run-credential.d.ts +61 -0
  225. package/dist/shared/run-credential.js +68 -0
  226. package/dist/shared/run-credential.js.map +1 -0
  227. package/dist/shared/skill-resolver.d.ts +3 -3
  228. package/dist/shared/skill-resolver.js +3 -3
  229. package/dist/shared/status-offload.d.ts +1 -1
  230. package/dist/shared/status-offload.js +2 -2
  231. package/dist/shared/status-offload.js.map +1 -1
  232. package/dist/shared/streaming-scheduler.d.ts +2 -7
  233. package/dist/shared/streaming-scheduler.js +6 -14
  234. package/dist/shared/streaming-scheduler.js.map +1 -1
  235. package/dist/shared/subagent-rows.d.ts +2 -2
  236. package/dist/shared/subagent-rows.js +2 -2
  237. package/dist/shared/synthesized-attachment.d.ts +30 -3
  238. package/dist/shared/synthesized-attachment.js +26 -0
  239. package/dist/shared/synthesized-attachment.js.map +1 -1
  240. package/dist/shared/todos.d.ts +3 -3
  241. package/dist/shared/todos.js +3 -3
  242. package/dist/shared/tool-row.d.ts +19 -1
  243. package/dist/shared/tool-row.js +36 -2
  244. package/dist/shared/tool-row.js.map +1 -1
  245. package/dist/shared/worker-shutdown.d.ts +1 -1
  246. package/dist/shared/worker-shutdown.js +1 -1
  247. package/dist/shared/workspace/session-provision.d.ts +1 -1
  248. package/dist/shared/workspace/session-provision.js +1 -1
  249. package/dist/shared/workspace/sources/empty.d.ts +1 -1
  250. package/dist/shared/workspace/sources/empty.js +1 -2
  251. package/dist/shared/workspace/sources/empty.js.map +1 -1
  252. package/dist/shared/workspace/sources/git.js +4 -4
  253. package/dist/shared/workspace/sources/git.js.map +1 -1
  254. package/dist/shared/workspace/sources/local-path.js +6 -6
  255. package/dist/shared/workspace/sources/local-path.js.map +1 -1
  256. package/dist/shared/workspace/stigmer-link.d.ts +1 -1
  257. package/dist/shared/workspace/stigmer-link.js +1 -1
  258. package/dist/shared/workspace/types.d.ts +2 -5
  259. package/dist/shared/workspace/types.js +0 -6
  260. package/dist/shared/workspace/types.js.map +1 -1
  261. package/dist/shared/workspace/writeback-coordinator.d.ts +17 -4
  262. package/dist/shared/workspace/writeback-coordinator.js +7 -9
  263. package/dist/shared/workspace/writeback-coordinator.js.map +1 -1
  264. package/dist/worker.js +10 -3
  265. package/dist/worker.js.map +1 -1
  266. package/dist/workflow-source.d.ts +10 -0
  267. package/dist/workflow-source.js +12 -0
  268. package/dist/workflow-source.js.map +1 -1
  269. package/dist/workflows/execute-from-execution.d.ts +15 -0
  270. package/dist/workflows/execute-from-execution.js +11 -0
  271. package/dist/workflows/execute-from-execution.js.map +1 -1
  272. package/dist/workflows/index.d.ts +5 -3
  273. package/dist/workflows/index.js +5 -3
  274. package/dist/workflows/index.js.map +1 -1
  275. package/dist/workflows/interceptors/run-credential.d.ts +34 -0
  276. package/dist/workflows/interceptors/run-credential.js +71 -0
  277. package/dist/workflows/interceptors/run-credential.js.map +1 -0
  278. package/package.json +4 -4
  279. package/src/__test-utils__/__tests__/execution-record-barrier.test.ts +70 -0
  280. package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +35 -1
  281. package/src/__test-utils__/approval-contract/contract.ts +1 -1
  282. package/src/__test-utils__/approval-contract/types.ts +1 -1
  283. package/src/__test-utils__/harness-boot-order-child.ts +1 -1
  284. package/src/__test-utils__/harness-contract/contract.ts +8 -8
  285. package/src/__test-utils__/harness-contract/recording-sink.ts +11 -1
  286. package/src/__test-utils__/harness-contract/runtime-contract.ts +52 -16
  287. package/src/__test-utils__/harness-contract/scripted-adapter.ts +47 -43
  288. package/src/__test-utils__/hermetic-activity.ts +113 -9
  289. package/src/__test-utils__/model-registry-fixture.ts +31 -7
  290. package/src/__test-utils__/module-specifiers.ts +32 -3
  291. package/src/__tests__/harness-boot-order.test.ts +1 -1
  292. package/src/__tests__/harness-contract.test.ts +1 -1
  293. package/src/__tests__/run-credential-e2e.test.ts +233 -0
  294. package/src/__tests__/run-credential-registration.test.ts +80 -0
  295. package/src/__tests__/runner-manager.test.ts +1 -1
  296. package/src/activities/__tests__/generate-session-subject-wire.test.ts +119 -0
  297. package/src/activities/execute-cursor/__test-utils__/__tests__/scripted-double.test.ts +1 -1
  298. package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +2 -2
  299. package/src/activities/execute-cursor/__test-utils__/fold.ts +116 -0
  300. package/src/activities/execute-cursor/__test-utils__/gateway-substrate.ts +1 -1
  301. package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +67 -17
  302. package/src/activities/execute-cursor/__test-utils__/scripted-agent.ts +19 -5
  303. package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +2 -1
  304. package/src/activities/execute-cursor/__tests__/approval-state.test.ts +14 -21
  305. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +3 -3
  306. package/src/activities/execute-cursor/__tests__/coarse-fingerprint.test.ts +2 -1
  307. package/src/activities/execute-cursor/__tests__/cursor-event-recorder.test.ts +142 -0
  308. package/src/activities/execute-cursor/__tests__/cursor-fetch-interceptor-bypass.test.ts +19 -8
  309. package/src/activities/execute-cursor/__tests__/cursor-sdk-auth-smoke.test.ts +10 -8
  310. package/src/activities/execute-cursor/__tests__/cursor-transcript-live.test.ts +298 -0
  311. package/src/activities/execute-cursor/__tests__/deny-gate-exact-apply.test.ts +4 -2
  312. package/src/activities/execute-cursor/__tests__/fetch-interceptor.test.ts +1 -1
  313. package/src/activities/execute-cursor/__tests__/hermetic/deny-and-retry.test.ts +1 -1
  314. package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +1 -1
  315. package/src/activities/execute-cursor/__tests__/hermetic/goldens/mcp-tool-call.status.json +71 -0
  316. package/src/activities/execute-cursor/__tests__/hermetic/goldens/sdk-task-note.status.json +73 -0
  317. package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.error-delta.status.json +78 -0
  318. package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.output-first.status.json +72 -0
  319. package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.status.json +72 -0
  320. package/src/activities/execute-cursor/__tests__/hermetic/goldens/sub-agent-delegation.status.json +109 -0
  321. package/src/activities/execute-cursor/__tests__/hermetic/goldens/thinking-turn.status.json +78 -0
  322. package/src/activities/execute-cursor/__tests__/hermetic/goldens/todo-write.status.json +119 -0
  323. package/src/activities/execute-cursor/__tests__/hermetic/goldens/tool-error.status.json +68 -0
  324. package/src/activities/execute-cursor/__tests__/hermetic/goldens/tool-only-step.status.json +67 -0
  325. package/src/activities/execute-cursor/__tests__/hermetic/goldens/unattributed-hook-block.status.json +1 -1
  326. package/src/activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts +7 -7
  327. package/src/activities/execute-cursor/__tests__/hermetic/mcp-tool-call.test.ts +146 -0
  328. package/src/activities/execute-cursor/__tests__/hermetic/pause-vs-shutdown.test.ts +5 -5
  329. package/src/activities/execute-cursor/__tests__/hermetic/plain-turn.test.ts +2 -1
  330. package/src/activities/execute-cursor/__tests__/hermetic/run-wait-arms.test.ts +2 -1
  331. package/src/activities/execute-cursor/__tests__/hermetic/sdk-task-note.test.ts +122 -0
  332. package/src/activities/execute-cursor/__tests__/hermetic/shell-output-delta.test.ts +276 -0
  333. package/src/activities/execute-cursor/__tests__/hermetic/stream-self-stop-arms.test.ts +8 -8
  334. package/src/activities/execute-cursor/__tests__/hermetic/sub-agent-delegation.test.ts +196 -0
  335. package/src/activities/execute-cursor/__tests__/hermetic/thinking-turn.test.ts +145 -0
  336. package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +1 -1
  337. package/src/activities/execute-cursor/__tests__/hermetic/todo-write.test.ts +165 -0
  338. package/src/activities/execute-cursor/__tests__/hermetic/tool-call.test.ts +3 -3
  339. package/src/activities/execute-cursor/__tests__/hermetic/tool-error.test.ts +138 -0
  340. package/src/activities/execute-cursor/__tests__/hermetic/tool-only-step.test.ts +130 -0
  341. package/src/activities/execute-cursor/__tests__/hermetic/unattributed-hook-block.test.ts +13 -1
  342. package/src/activities/execute-cursor/__tests__/hermetic/workspace-lock-timeout.test.ts +2 -2
  343. package/src/activities/execute-cursor/__tests__/hitl-ledger.test.ts +43 -60
  344. package/src/activities/execute-cursor/__tests__/hitl-resume-history.test.ts +23 -28
  345. package/src/activities/execute-cursor/__tests__/hook-script.test.ts +2 -1
  346. package/src/activities/execute-cursor/__tests__/http2-interceptor.test.ts +1 -1
  347. package/src/activities/execute-cursor/__tests__/prompt-goldens.test.ts +5 -5
  348. package/src/activities/execute-cursor/__tests__/same-identity-reproposal.test.ts +11 -13
  349. package/src/activities/execute-cursor/__tests__/sequential-gate-resume.test.ts +8 -11
  350. package/src/activities/execute-cursor/__tests__/tool-result-image.test.ts +8 -22
  351. package/src/activities/execute-cursor/__tests__/translator.test.ts +594 -0
  352. package/src/activities/execute-cursor/__tests__/turn-boundary.test.ts +8 -5
  353. package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +87 -63
  354. package/src/activities/execute-cursor/adapter.ts +4 -4
  355. package/src/activities/execute-cursor/approval-policy.ts +12 -24
  356. package/src/activities/execute-cursor/approval-state.ts +66 -1
  357. package/src/activities/execute-cursor/boundary-rows.ts +1132 -0
  358. package/src/activities/execute-cursor/cursor-capabilities.ts +1 -1
  359. package/src/activities/execute-cursor/cursor-event-recorder.ts +57 -28
  360. package/src/activities/execute-cursor/fetch-interceptor.ts +1 -1
  361. package/src/activities/execute-cursor/http2-interceptor.ts +1 -1
  362. package/src/activities/execute-cursor/prompt-builder.ts +6 -6
  363. package/src/activities/execute-cursor/service-tier.ts +1 -2
  364. package/src/activities/execute-cursor/sub-agent-steps.ts +188 -0
  365. package/src/activities/execute-cursor/tool-result.ts +128 -0
  366. package/src/activities/execute-cursor/translator.ts +541 -0
  367. package/src/activities/execute-cursor/turn-boundary.ts +21 -14
  368. package/src/activities/execute-cursor/turn-settle.ts +46 -34
  369. package/src/activities/execute-cursor/turn-setup.ts +5 -5
  370. package/src/activities/execute-cursor/turn-stream.ts +49 -46
  371. package/src/activities/execute-cursor/turn.ts +5 -5
  372. package/src/activities/execute-cursor/usage-pricing.ts +2 -2
  373. package/src/activities/execute-deep-agent/__test-utils__/contract-subject.ts +2 -2
  374. package/src/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.ts +23 -11
  375. package/src/activities/execute-deep-agent/__test-utils__/hitl-script.ts +1 -1
  376. package/src/activities/execute-deep-agent/__test-utils__/scripted-model-module.ts +2 -3
  377. package/src/activities/execute-deep-agent/__test-utils__/scripted-model.ts +25 -4
  378. package/src/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.ts +25 -11
  379. package/src/activities/execute-deep-agent/__tests__/adapter-graph-is-sdk-free.test.ts +1 -1
  380. package/src/activities/execute-deep-agent/__tests__/adapter-is-temporal-free.test.ts +1 -1
  381. package/src/activities/execute-deep-agent/__tests__/approval-file-change.test.ts +6 -17
  382. package/src/activities/execute-deep-agent/__tests__/hermetic/file-review-capture.test.ts +25 -8
  383. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn1.status.json +2 -7
  384. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn2.status.json +4 -14
  385. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve.turn2.status.json +1 -5
  386. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/file-review-capture.status.json +4 -7
  387. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/gate.turn1.status.json +1 -5
  388. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn1.status.json +2 -9
  389. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn2.status.json +2 -9
  390. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.after-tool.status.json +1 -4
  391. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.mid-tool.status.json +1 -4
  392. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/platform-stop.status.json +1 -4
  393. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/recursion-limit.persisted.status.json +109 -76
  394. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/reject.turn2.status.json +1 -5
  395. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn2.status.json +2 -10
  396. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn3.status.json +2 -10
  397. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/skip.turn2.status.json +1 -5
  398. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sub-agent-delegation.status.json +3 -6
  399. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/tool-call.status.json +1 -4
  400. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/worker-shutdown.status.json +1 -4
  401. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/write-todos.status.json +92 -0
  402. package/src/activities/execute-deep-agent/__tests__/hermetic/harness-contract.test.ts +3 -3
  403. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-approve-all-lease.test.ts +9 -5
  404. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-round-trips.test.ts +3 -3
  405. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-sequential-gates.test.ts +3 -3
  406. package/src/activities/execute-deep-agent/__tests__/hermetic/inline-artifact-across-gate.test.ts +7 -6
  407. package/src/activities/execute-deep-agent/__tests__/hermetic/pause-vs-shutdown.test.ts +10 -11
  408. package/src/activities/execute-deep-agent/__tests__/hermetic/plain-turn.test.ts +4 -4
  409. package/src/activities/execute-deep-agent/__tests__/hermetic/platform-stop.test.ts +9 -8
  410. package/src/activities/execute-deep-agent/__tests__/hermetic/recursion-limit.test.ts +21 -13
  411. package/src/activities/execute-deep-agent/__tests__/hermetic/resolution-error.test.ts +2 -2
  412. package/src/activities/execute-deep-agent/__tests__/hermetic/structured-output.test.ts +7 -7
  413. package/src/activities/execute-deep-agent/__tests__/hermetic/sub-agent-delegation.test.ts +28 -12
  414. package/src/activities/execute-deep-agent/__tests__/hermetic/tool-call.test.ts +21 -21
  415. package/src/activities/execute-deep-agent/__tests__/hermetic/workspace-lock-timeout.test.ts +5 -5
  416. package/src/activities/execute-deep-agent/__tests__/hermetic/write-todos.test.ts +160 -0
  417. package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +35 -30
  418. package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +3 -4
  419. package/src/activities/execute-deep-agent/__tests__/prompt-goldens.test.ts +12 -10
  420. package/src/activities/execute-deep-agent/__tests__/scripted-model.test.ts +13 -3
  421. package/src/activities/execute-deep-agent/__tests__/streaming-side-effects.test.ts +26 -18
  422. package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +1 -1
  423. package/src/activities/execute-deep-agent/__tests__/{subagent-tracker.test.ts → translator-subagents.test.ts} +76 -57
  424. package/src/activities/execute-deep-agent/__tests__/{v3-status-builder.test.ts → translator-through-builder.test.ts} +213 -299
  425. package/src/activities/execute-deep-agent/__tests__/translator.test.ts +505 -0
  426. package/src/activities/execute-deep-agent/__tests__/turn-stream.test.ts +11 -29
  427. package/src/activities/execute-deep-agent/adapter.ts +1 -1
  428. package/src/activities/execute-deep-agent/approval-file-change.ts +20 -22
  429. package/src/activities/execute-deep-agent/deep-agent-capabilities.ts +2 -2
  430. package/src/activities/execute-deep-agent/hitl.ts +2 -2
  431. package/src/activities/execute-deep-agent/inline-publisher.ts +16 -5
  432. package/src/activities/execute-deep-agent/prompt-builder.ts +6 -7
  433. package/src/activities/execute-deep-agent/streaming-side-effects.ts +22 -31
  434. package/src/activities/execute-deep-agent/subagent-transformer.ts +3 -3
  435. package/src/activities/execute-deep-agent/translator.ts +463 -0
  436. package/src/activities/execute-deep-agent/turn-settle.ts +35 -43
  437. package/src/activities/execute-deep-agent/turn-setup.ts +8 -8
  438. package/src/activities/execute-deep-agent/turn-stream.ts +53 -51
  439. package/src/activities/execute-deep-agent/turn.ts +3 -3
  440. package/src/activities/generate-session-subject.ts +29 -4
  441. package/src/client/__tests__/stigmer-client.test.ts +92 -0
  442. package/src/client/stigmer-client.ts +48 -14
  443. package/src/config.ts +6 -3
  444. package/src/harness/README.md +335 -0
  445. package/src/harness/__tests__/approval-decisions.test.ts +2 -2
  446. package/src/harness/__tests__/capture.test.ts +3 -3
  447. package/src/harness/__tests__/import-direction.test.ts +3 -2
  448. package/src/harness/__tests__/mount-skills.test.ts +4 -1
  449. package/src/harness/__tests__/readme-index.test.ts +339 -0
  450. package/src/harness/__tests__/run-turn.test.ts +131 -6
  451. package/src/harness/__tests__/transcript-is-engine-free.test.ts +83 -0
  452. package/src/harness/__tests__/transcript-writers.test.ts +191 -0
  453. package/src/harness/__tests__/turn-attachments-vision.test.ts +5 -2
  454. package/src/harness/__tests__/turn-context.test.ts +5 -5
  455. package/src/harness/approval-decisions.ts +1 -1
  456. package/src/harness/capabilities.ts +21 -11
  457. package/src/harness/capture.ts +4 -4
  458. package/src/harness/persist-chokepoint.ts +3 -3
  459. package/src/harness/registry.ts +2 -2
  460. package/src/harness/run-turn.ts +33 -9
  461. package/src/harness/stop-controller.ts +1 -1
  462. package/src/harness/terminal-table.ts +7 -7
  463. package/src/harness/transcript/__tests__/builder.test.ts +975 -0
  464. package/src/harness/transcript/__tests__/state.test.ts +143 -0
  465. package/src/harness/transcript/builder.ts +755 -0
  466. package/src/harness/transcript/events.ts +262 -0
  467. package/src/harness/transcript/state.ts +167 -0
  468. package/src/harness/turn-context.ts +61 -46
  469. package/src/harness/types.ts +64 -22
  470. package/src/harness/usage-accumulator.ts +2 -2
  471. package/src/harness-adapters.ts +5 -4
  472. package/src/interceptors/__tests__/run-credential-activity.test.ts +133 -0
  473. package/src/interceptors/run-credential-activity.ts +67 -0
  474. package/src/middleware/__tests__/cost-advisory.test.ts +2 -2
  475. package/src/middleware/approval-gate.ts +7 -74
  476. package/src/middleware/cost-advisory.ts +3 -3
  477. package/src/middleware/index.ts +1 -1
  478. package/src/runner-manager.ts +14 -4
  479. package/src/shared/__tests__/approval-policy.test.ts +45 -0
  480. package/src/shared/__tests__/args-preview.test.ts +40 -20
  481. package/src/shared/__tests__/attachment-naming.test.ts +1 -1
  482. package/src/shared/__tests__/attachment-resolver.test.ts +5 -5
  483. package/src/shared/__tests__/attachment-zip.test.ts +1 -1
  484. package/src/shared/__tests__/blueprint-resolver.test.ts +1 -1
  485. package/src/shared/__tests__/channel-attachment.test.ts +12 -0
  486. package/src/shared/__tests__/cost-guard.test.ts +1 -1
  487. package/src/shared/__tests__/exact-apply.test.ts +2 -1
  488. package/src/shared/__tests__/memory-attachment.test.ts +17 -0
  489. package/src/shared/__tests__/persist-decision.test.ts +19 -33
  490. package/src/shared/__tests__/prompt-sections.test.ts +1 -1
  491. package/src/shared/__tests__/run-credential.test.ts +111 -0
  492. package/src/shared/__tests__/stamp-flowed-rows.test.ts +1 -1
  493. package/src/shared/__tests__/status-offload.test.ts +1 -1
  494. package/src/shared/__tests__/streaming-scheduler.test.ts +8 -9
  495. package/src/shared/__tests__/todos.test.ts +1 -1
  496. package/src/shared/__tests__/tool-row.test.ts +1 -1
  497. package/src/shared/activity-input.ts +21 -0
  498. package/src/shared/approval-policy.ts +95 -0
  499. package/src/shared/args-preview.ts +51 -42
  500. package/src/shared/attachment-resolver.ts +4 -4
  501. package/src/shared/attachment-zip.ts +2 -2
  502. package/src/shared/channel-attachment.ts +14 -6
  503. package/src/shared/cost-guard.ts +2 -2
  504. package/src/shared/exact-apply.ts +1 -1
  505. package/src/shared/execution-context.ts +2 -2
  506. package/src/shared/extract-structured-output.ts +2 -2
  507. package/src/shared/filereview/__tests__/capture.test.ts +9 -5
  508. package/src/shared/filereview/__tests__/git-substrate.test.ts +4 -1
  509. package/src/shared/filereview/__tests__/proxy-reconcile.test.ts +3 -3
  510. package/src/shared/filereview/cas-touched.ts +2 -2
  511. package/src/shared/filereview/progress.ts +13 -0
  512. package/src/shared/heartbeat.ts +1 -1
  513. package/src/shared/llm-backend.ts +0 -4
  514. package/src/shared/memory-attachment.ts +22 -10
  515. package/src/shared/model-error.ts +1 -2
  516. package/src/shared/persist-decision.ts +19 -28
  517. package/src/shared/prompt-sections.ts +4 -4
  518. package/src/shared/run-credential-store.ts +45 -0
  519. package/src/shared/run-credential.ts +70 -0
  520. package/src/shared/skill-resolver.ts +3 -3
  521. package/src/shared/status-offload.ts +2 -2
  522. package/src/shared/streaming-scheduler.ts +8 -13
  523. package/src/shared/subagent-rows.ts +2 -2
  524. package/src/shared/synthesized-attachment.ts +38 -3
  525. package/src/shared/todos.ts +3 -3
  526. package/src/shared/tool-row.ts +38 -2
  527. package/src/shared/worker-shutdown.ts +1 -1
  528. package/src/shared/workspace/__tests__/git-source.test.ts +3 -3
  529. package/src/shared/workspace/__tests__/provisioner.test.ts +5 -5
  530. package/src/shared/workspace/__tests__/session-provision.test.ts +2 -2
  531. package/src/shared/workspace/__tests__/writeback-coordinator.integration.test.ts +8 -9
  532. package/src/shared/workspace/__tests__/writeback-coordinator.test.ts +25 -25
  533. package/src/shared/workspace/provisioner.ts +1 -1
  534. package/src/shared/workspace/session-provision.ts +1 -1
  535. package/src/shared/workspace/sources/empty.ts +2 -2
  536. package/src/shared/workspace/sources/git.ts +3 -4
  537. package/src/shared/workspace/sources/local-path.ts +5 -6
  538. package/src/shared/workspace/stigmer-link.ts +1 -1
  539. package/src/shared/workspace/types.ts +2 -5
  540. package/src/shared/workspace/writeback-coordinator.ts +23 -12
  541. package/src/worker.ts +15 -3
  542. package/src/workflow-source.ts +15 -0
  543. package/src/workflows/__tests__/run-credential-interceptor.test.ts +178 -0
  544. package/src/workflows/execute-from-execution.ts +17 -0
  545. package/src/workflows/index.ts +5 -3
  546. package/src/workflows/interceptors/run-credential.ts +101 -0
  547. package/dist/activities/execute-cursor/delta-enricher.d.ts +0 -87
  548. package/dist/activities/execute-cursor/delta-enricher.js +0 -265
  549. package/dist/activities/execute-cursor/delta-enricher.js.map +0 -1
  550. package/dist/activities/execute-cursor/message-translator.js +0 -2040
  551. package/dist/activities/execute-cursor/message-translator.js.map +0 -1
  552. package/dist/activities/execute-cursor/todo-tracker.d.ts +0 -40
  553. package/dist/activities/execute-cursor/todo-tracker.js +0 -80
  554. package/dist/activities/execute-cursor/todo-tracker.js.map +0 -1
  555. package/dist/activities/execute-deep-agent/execution-state.d.ts +0 -54
  556. package/dist/activities/execute-deep-agent/execution-state.js +0 -68
  557. package/dist/activities/execute-deep-agent/execution-state.js.map +0 -1
  558. package/dist/activities/execute-deep-agent/status-builder-shared.d.ts +0 -65
  559. package/dist/activities/execute-deep-agent/status-builder-shared.js +0 -90
  560. package/dist/activities/execute-deep-agent/status-builder-shared.js.map +0 -1
  561. package/dist/activities/execute-deep-agent/subagent-tracker.d.ts +0 -113
  562. package/dist/activities/execute-deep-agent/subagent-tracker.js +0 -400
  563. package/dist/activities/execute-deep-agent/subagent-tracker.js.map +0 -1
  564. package/dist/activities/execute-deep-agent/v3-events.d.ts +0 -102
  565. package/dist/activities/execute-deep-agent/v3-events.js +0 -35
  566. package/dist/activities/execute-deep-agent/v3-events.js.map +0 -1
  567. package/dist/activities/execute-deep-agent/v3-protocol-normalizer.d.ts +0 -15
  568. package/dist/activities/execute-deep-agent/v3-protocol-normalizer.js +0 -235
  569. package/dist/activities/execute-deep-agent/v3-protocol-normalizer.js.map +0 -1
  570. package/dist/activities/execute-deep-agent/v3-status-builder.d.ts +0 -111
  571. package/dist/activities/execute-deep-agent/v3-status-builder.js +0 -457
  572. package/dist/activities/execute-deep-agent/v3-status-builder.js.map +0 -1
  573. package/dist/shared/execution-status-writer.d.ts +0 -31
  574. package/dist/shared/execution-status-writer.js +0 -43
  575. package/dist/shared/execution-status-writer.js.map +0 -1
  576. package/src/activities/execute-cursor/__tests__/delta-enricher.test.ts +0 -310
  577. package/src/activities/execute-cursor/__tests__/message-translator.test.ts +0 -1033
  578. package/src/activities/execute-cursor/__tests__/todo-tracker.test.ts +0 -498
  579. package/src/activities/execute-cursor/delta-enricher.ts +0 -307
  580. package/src/activities/execute-cursor/message-translator.ts +0 -2319
  581. package/src/activities/execute-cursor/todo-tracker.ts +0 -91
  582. package/src/activities/execute-deep-agent/__tests__/execution-state-extended.test.ts +0 -148
  583. package/src/activities/execute-deep-agent/__tests__/execution-state.test.ts +0 -154
  584. package/src/activities/execute-deep-agent/__tests__/status-builder-shared.test.ts +0 -47
  585. package/src/activities/execute-deep-agent/__tests__/v3-protocol-normalizer.test.ts +0 -324
  586. package/src/activities/execute-deep-agent/execution-state.ts +0 -78
  587. package/src/activities/execute-deep-agent/status-builder-shared.ts +0 -142
  588. package/src/activities/execute-deep-agent/subagent-tracker.ts +0 -479
  589. package/src/activities/execute-deep-agent/v3-events.ts +0 -153
  590. package/src/activities/execute-deep-agent/v3-protocol-normalizer.ts +0 -264
  591. package/src/activities/execute-deep-agent/v3-status-builder.ts +0 -565
  592. package/src/shared/execution-status-writer.ts +0 -56
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Hermetic golden: an MCP TOOL CALL — the SDK reports the call as `name: "mcp"`
3
+ * and packs the real identity into its args — through the whole
4
+ * `ExecuteCursor` activity.
5
+ *
6
+ * Invariant pinned: the translator unwraps
7
+ * `{ providerIdentifier, toolName, args }` from the event's args
8
+ * (`extractMcpToolDetails`) and the row is the INNER tool: `name` is `toolName`,
9
+ * `mcpServerSlug` is `providerIdentifier`, `args` is the inner args,
10
+ * `toolKind` is MCP, and `argsPreview` is the elided preview of the row's OWN
11
+ * `args` — `{"query":"fixture"}` — through the platform's one sanitizer. With
12
+ * no MCP server declared on the record there is no policy for the tool, so it
13
+ * is not gated; the provenance stamp still names the layer that cleared it.
14
+ *
15
+ * Moved 2026-09-14 (#1097), the ONE hunk this golden was
16
+ * predicted to take: until then the stream path stamped the OUTER
17
+ * `{ providerIdentifier, toolName, args }` envelope stringified — the
18
+ * envelope, not the arguments. The canonical builder derives every row's
19
+ * preview from its `args` and never from an engine's envelope; the
20
+ * accumulator was aligned to that rule before the swap to the shared builder,
21
+ * so the swap moved nothing.
22
+ *
23
+ * Why this net exists: no earlier Cursor golden carried an MCP-attributed
24
+ * row, and #1097 moved the unwrapping whole into the Cursor translator.
25
+ *
26
+ * Regenerate ONLY after a deliberate behavior change:
27
+ * npx vitest run src/activities/execute-cursor/__tests__/hermetic -u
28
+ */
29
+
30
+ import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
31
+ import { toJson } from "@bufbuild/protobuf";
32
+ import { AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
33
+ import { ExecutionPhase, ToolCallStatus, ToolKind } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
34
+
35
+ vi.mock("@cursor/sdk", async () =>
36
+ (await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSdkModule(),
37
+ );
38
+ vi.mock("../../../../client/stigmer-client.js", async () =>
39
+ (await import("../../../../__test-utils__/hermetic-activity.js")).hermeticStigmerClientModule(),
40
+ );
41
+
42
+ import {
43
+ ScriptedClock,
44
+ createHermeticEnvironment,
45
+ type HermeticEnvironment,
46
+ } from "../../../../__test-utils__/hermetic-activity.js";
47
+ import { ScriptedCursorAgent, sdkEvents, step } from "../../__test-utils__/scripted-agent.js";
48
+ import {
49
+ FIXTURE,
50
+ SDK_CATALOG,
51
+ beginCursorScenario,
52
+ cursorExecutionRecord,
53
+ runCursorTurn,
54
+ } from "../../__test-utils__/hermetic-cursor.js";
55
+ import { stubRegistryFetch } from "../../../../__test-utils__/model-registry-fixture.js";
56
+
57
+ const AGENT_ID = "agent-hermetic-mcp-0001";
58
+ const RUN_ID = "run-hermetic-mcp-0001";
59
+ const CALL_ID = "call-hermetic-mcp-0001";
60
+ const USER_MESSAGE = "Search the docs for the fixture.";
61
+ const TEXT_BEFORE = "Searching the docs.";
62
+ const MCP_SERVER = "hermetic-docs";
63
+ const MCP_TOOL = "search_docs";
64
+ const INNER_ARGS = { query: "fixture" };
65
+ /** The SDK's MCP envelope: the real identity is inside the `mcp` call's args. */
66
+ const MCP_EVENT_ARGS = { providerIdentifier: MCP_SERVER, toolName: MCP_TOOL, args: INNER_ARGS };
67
+ const MCP_RESULT = "1 result: README.md — A fixture readme.";
68
+ const TEXT_AFTER = "One document mentions the fixture: README.md.";
69
+
70
+ describe("ExecuteCursor hermetic — MCP tool call", () => {
71
+ let env: HermeticEnvironment;
72
+ let registry: ReturnType<typeof stubRegistryFetch>;
73
+ const clock = new ScriptedClock();
74
+
75
+ beforeAll(() => {
76
+ env = createHermeticEnvironment();
77
+ registry = stubRegistryFetch();
78
+ clock.install();
79
+ });
80
+
81
+ afterAll(() => {
82
+ clock.uninstall();
83
+ registry.restore();
84
+ env.dispose();
85
+ });
86
+
87
+ it("writes the row as the inner tool with its server slug and completes", async () => {
88
+ // ── Arrange ──────────────────────────────────────────────────────────────
89
+ const ev = sdkEvents(AGENT_ID, RUN_ID);
90
+ const agent = new ScriptedCursorAgent({
91
+ agentId: AGENT_ID,
92
+ runIds: [RUN_ID],
93
+ observeStep: () => clock.tick(),
94
+ turns: [
95
+ [
96
+ step.event(ev.init()),
97
+ step.event(ev.assistant(TEXT_BEFORE)),
98
+ step.event(ev.toolCall(CALL_ID, "mcp", "running", MCP_EVENT_ARGS)),
99
+ step.event(ev.toolCall(CALL_ID, "mcp", "completed", MCP_EVENT_ARGS, MCP_RESULT)),
100
+ step.event(ev.assistant(TEXT_AFTER)),
101
+ step.turnEnded({ inputTokens: 2_100, outputTokens: 80, cacheReadTokens: 0, cacheWriteTokens: 0 }),
102
+ step.finished({ result: TEXT_AFTER, model: { id: FIXTURE.model, params: [] } }),
103
+ ],
104
+ ],
105
+ });
106
+ const record = cursorExecutionRecord({ message: USER_MESSAGE });
107
+ const scenario = beginCursorScenario({
108
+ env,
109
+ clock,
110
+ record,
111
+ sdk: { agents: [agent], catalog: SDK_CATALOG },
112
+ });
113
+
114
+ // ── Act ──────────────────────────────────────────────────────────────────
115
+ const invocation = await runCursorTurn(scenario);
116
+
117
+ // ── Assert: outcome ──────────────────────────────────────────────────────
118
+ expect(invocation.outcome.kind).toBe("returned");
119
+ expect((invocation.outcome as { value: Record<string, unknown> }).value.phase).toBe("EXECUTION_COMPLETED");
120
+ expect(record.persistedPhases.at(-1)).toBe(ExecutionPhase.EXECUTION_COMPLETED);
121
+
122
+ // ── Assert: the attributed row ───────────────────────────────────────────
123
+ const rows = record.toolCalls();
124
+ expect(rows).toHaveLength(1);
125
+ const row = rows[0];
126
+ expect(row.id).toBe(CALL_ID);
127
+ expect(row.name, "the inner tool, never the `mcp` envelope").toBe(MCP_TOOL);
128
+ expect(row.mcpServerSlug).toBe(MCP_SERVER);
129
+ expect(row.toolKind).toBe(ToolKind.MCP);
130
+ expect(row.args, "the inner args").toEqual(INNER_ARGS);
131
+ expect(row.argsPreview, "the row's own args, never the engine's envelope").toBe(
132
+ JSON.stringify(INNER_ARGS),
133
+ );
134
+ expect(row.status).toBe(ToolCallStatus.TOOL_CALL_COMPLETED);
135
+ expect(row.result).toBe(MCP_RESULT);
136
+ expect(row.requiresApproval, "no server declared, no policy, not gated").toBe(false);
137
+
138
+ // ── Assert: hermeticity ──────────────────────────────────────────────────
139
+ expect(registry.urls.every((u) => u.includes("/model-registry"))).toBe(true);
140
+
141
+ // ── Assert: the golden ───────────────────────────────────────────────────
142
+ const final = record.lastFullStatus!;
143
+ const json = JSON.stringify(toJson(AgentExecutionStatusSchema, final), null, 2) + "\n";
144
+ await expect(json).toMatchFileSnapshot("./goldens/mcp-tool-call.status.json");
145
+ });
146
+ });
@@ -26,8 +26,8 @@
26
26
  * ONCE. The orchestrator this net was recorded on appended it twice — once in
27
27
  * `resolvePreBoundaryTerminal` before the throw, once again in the outer
28
28
  * `catch (CancelledFailure)`, which re-stamped and re-persisted — and the
29
- * goldens pinned that double on purpose so S2 could reproduce the wire byte
30
- * for byte (stigmer#1054, Q-S2-4). The runtime's `settleWith` is now the one
29
+ * goldens pinned that double on purpose so #1070 could reproduce the wire byte
30
+ * for byte (removed in stigmer#1054). The runtime's `settleWith` is now the one
31
31
  * writer of a terminal arm, so a second row has no code path to come from.
32
32
  *
33
33
  * Runtime phases exercised: the adapter's stop-signal cancel; the runtime's
@@ -35,11 +35,11 @@
35
35
  * arms through `settleWith`; the `finally` teardown under a thrown exit.
36
36
  *
37
37
  * Regeneration history:
38
- * - S2 M3b (entry 20260911.03): timestamp-only diff — every terminal stamp
38
+ * - #1070: timestamp-only diff — every terminal stamp
39
39
  * one scripted second earlier: the adapter cancels the SDK run the instant
40
- * the runtime's stop signal aborts (Q-M3-4), before the SDK double pulls,
40
+ * the runtime's stop signal aborts, before the SDK double pulls,
41
41
  * and the clock ticks on, one more step. Transcript unchanged.
42
- * - 2026-09-12 (stigmer#1054, the PR after S2): one removed system row per
42
+ * - 2026-09-12 (stigmer#1054, the PR after #1070): one removed system row per
43
43
  * golden, nothing else. The transcript now carries each terminal row once.
44
44
  *
45
45
  * Regenerate ONLY after a deliberate behavior change:
@@ -9,7 +9,8 @@
9
9
  * scenario is a delta from, and the first proof that the activity is byte-
10
10
  * stable under the hermetic driver.
11
11
  *
12
- * Parent phase rows exercised (20260908.02 `T01_0_plan.md` §3a): normalize
12
+ * Phase rows of the pre-runtime orchestrator this net was recorded against
13
+ * (#1048): normalize
13
14
  * input / heartbeat; artifact storage + the `persist` chokepoint; fetch
14
15
  * execution, session, agent, blueprint; resolve environment (NOT_FOUND ->
15
16
  * empty); provision workspace (per-session dir); workspace turn lock; MCP
@@ -5,7 +5,8 @@
5
5
  * Phase 13 of the activity maps what the SDK's `run.wait()` resolves into a
6
6
  * terminal phase, and the `error` case is where the error classifier decides
7
7
  * whether the runner tries again on its own. The three scenarios here pin the
8
- * three outcomes of that decision table that the S0 net did not cover (the
8
+ * three outcomes of that decision table that the first hermetic net (#1048)
9
+ * did not cover (the
9
10
  * poisoned-handle recovery on a RESUMED agent is `recovery-fresh-agent.test.ts`):
10
11
  *
11
12
  * 1. A NON-RETRYABLE error (auth class): the classifier files it as
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Hermetic golden: the SDK's `task` event — a status line about the run in
3
+ * the agent's own voice — between two assistant messages, through the whole
4
+ * `ExecuteCursor` activity.
5
+ *
6
+ * Invariant pinned (#1097; until then this event had no test on either
7
+ * tier): a `task` event with text becomes ONE SYSTEM
8
+ * message at its position in the transcript (`translateTask`); it hosts no
9
+ * tool rows and does not move the AI-message boundary — the tool call that
10
+ * follows it lands on the assistant message BEFORE the note, and the text
11
+ * after the tool call is a new message. A `task` event with no text produces
12
+ * nothing.
13
+ *
14
+ * Predicted for the swap to the shared builder: NO move. The translator
15
+ * maps `task.text` to the union's `system_note`, which the builder
16
+ * appends as a SYSTEM message in the scope with the same placement rule.
17
+ *
18
+ * Regenerate ONLY after a deliberate behavior change:
19
+ * npx vitest run src/activities/execute-cursor/__tests__/hermetic -u
20
+ */
21
+
22
+ import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
23
+ import { toJson } from "@bufbuild/protobuf";
24
+ import { AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
25
+ import { ExecutionPhase, MessageType } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
26
+
27
+ vi.mock("@cursor/sdk", async () =>
28
+ (await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSdkModule(),
29
+ );
30
+ vi.mock("@cursor/sdk/sqlite", async () =>
31
+ (await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSqliteModule(),
32
+ );
33
+ vi.mock("../../../../client/stigmer-client.js", async () =>
34
+ (await import("../../../../__test-utils__/hermetic-activity.js")).hermeticStigmerClientModule(),
35
+ );
36
+
37
+ import {
38
+ ScriptedClock,
39
+ createHermeticEnvironment,
40
+ type HermeticEnvironment,
41
+ } from "../../../../__test-utils__/hermetic-activity.js";
42
+ import { ScriptedCursorAgent, sdkEvents, step } from "../../__test-utils__/scripted-agent.js";
43
+ import {
44
+ FIXTURE,
45
+ SDK_CATALOG,
46
+ beginCursorScenario,
47
+ cursorExecutionRecord,
48
+ runCursorTurn,
49
+ } from "../../__test-utils__/hermetic-cursor.js";
50
+ import { stubRegistryFetch } from "../../../../__test-utils__/model-registry-fixture.js";
51
+
52
+ const AGENT_ID = "agent-hermetic-tasknote-0001";
53
+ const RUN_ID = "run-hermetic-tasknote-0001";
54
+ const CALL_ID = "call-hermetic-tasknote-read-0001";
55
+ const USER_MESSAGE = "Summarise README.md.";
56
+ const TEXT_BEFORE = "Reading the file first.";
57
+ const TASK_NOTE = "Scanning the workspace for the file.";
58
+ const READ_ARGS = { path: "README.md" };
59
+ const READ_RESULT = "# Hermetic\n\nA fixture readme.\n";
60
+ const TEXT_AFTER = "README.md is a one-line fixture description.";
61
+
62
+ describe("ExecuteCursor hermetic — the SDK's task event as a system note", () => {
63
+ let env: HermeticEnvironment;
64
+ let registry: ReturnType<typeof stubRegistryFetch>;
65
+ const clock = new ScriptedClock();
66
+
67
+ beforeAll(() => {
68
+ env = createHermeticEnvironment();
69
+ registry = stubRegistryFetch();
70
+ clock.install();
71
+ });
72
+
73
+ afterAll(() => {
74
+ clock.uninstall();
75
+ registry.restore();
76
+ env.dispose();
77
+ });
78
+
79
+ it("places the note as a SYSTEM message that hosts no rows and moves no boundary; an empty note produces nothing", async () => {
80
+ const ev = sdkEvents(AGENT_ID, RUN_ID);
81
+ const agent = new ScriptedCursorAgent({
82
+ agentId: AGENT_ID,
83
+ runIds: [RUN_ID],
84
+ observeStep: () => clock.tick(),
85
+ turns: [
86
+ [
87
+ step.event(ev.init()),
88
+ step.event(ev.assistant(TEXT_BEFORE)),
89
+ step.event(ev.task(TASK_NOTE, "running")),
90
+ step.event(ev.task("", "running")),
91
+ step.event(ev.toolCall(CALL_ID, "read", "running", READ_ARGS)),
92
+ step.event(ev.toolCall(CALL_ID, "read", "completed", READ_ARGS, READ_RESULT)),
93
+ step.event(ev.assistant(TEXT_AFTER)),
94
+ step.turnEnded({ inputTokens: 1_800, outputTokens: 50, cacheReadTokens: 0, cacheWriteTokens: 0 }),
95
+ step.finished({ result: TEXT_AFTER, model: { id: FIXTURE.model, params: [] } }),
96
+ ],
97
+ ],
98
+ });
99
+ const record = cursorExecutionRecord({ message: USER_MESSAGE });
100
+ const scenario = beginCursorScenario({ env, clock, record, sdk: { agents: [agent], catalog: SDK_CATALOG } });
101
+
102
+ const invocation = await runCursorTurn(scenario);
103
+
104
+ expect(invocation.outcome.kind).toBe("returned");
105
+ expect(record.persistedPhases.at(-1)).toBe(ExecutionPhase.EXECUTION_COMPLETED);
106
+
107
+ const messages = record.lastFullStatus!.messages;
108
+ expect(messages.map((m) => m.type), "AI, the note, AI").toEqual([
109
+ MessageType.MESSAGE_AI,
110
+ MessageType.MESSAGE_SYSTEM,
111
+ MessageType.MESSAGE_AI,
112
+ ]);
113
+ expect(messages[1].content).toBe(TASK_NOTE);
114
+ expect(messages[1].toolCalls, "a note hosts no rows").toHaveLength(0);
115
+ expect(messages[0].toolCalls.map((tc) => tc.id), "the row lands on the assistant message before the note").toEqual([CALL_ID]);
116
+ expect(messages[2].content).toBe(TEXT_AFTER);
117
+ expect(registry.urls.every((u) => u.includes("/model-registry"))).toBe(true);
118
+
119
+ const json = JSON.stringify(toJson(AgentExecutionStatusSchema, record.lastFullStatus!), null, 2) + "\n";
120
+ await expect(json).toMatchFileSnapshot("./goldens/sdk-task-note.status.json");
121
+ });
122
+ });
@@ -0,0 +1,276 @@
1
+ /**
2
+ * Hermetic goldens: the SDK's DELTA CHANNEL folding onto a shell tool's row —
3
+ * `tool-call-started`, `shell-output-delta` and `tool-call-completed` fired
4
+ * through `onDelta` between the stream's own `tool_call` events — through the
5
+ * whole `ExecuteCursor` activity.
6
+ *
7
+ * Why this net exists (#1097): the scripted double emitted only the
8
+ * `turn-ended` usage delta until then, so the rule that PR changed most —
9
+ * a completion learned from the timing delta and merged with the stream's
10
+ * later completion — had no end-to-end net; `delta-enricher.ts`'s
11
+ * twelve unit arms were the whole of it. The three arms below were pinned
12
+ * on the enricher's fold before the swap to the shared builder, and each
13
+ * header states what was predicted to move at the swap and after it.
14
+ *
15
+ * Arm 1 — the ordinary order. The stream's `running` creates the row; the
16
+ * deltas arrive; the stream's `completed` settles it. Pinned: `startedAt` is
17
+ * the stream's `running` instant; the live output reaches `result`
18
+ * (`streamingSource: OUTPUT` while it streams, cleared at finalize); the
19
+ * stream's `completed` stamps `completedAt` and its result wins; the shell
20
+ * row is a gated built-in (`requiresApproval`, "Run command: …") that the
21
+ * hook never saw, so no `approvalRequestedAt`. Predicted: NO move (the
22
+ * translator drains the queued deltas AFTER the stream event of the
23
+ * same window, as the enricher applied them, so the stream's instant wins
24
+ * exactly as before).
25
+ *
26
+ * Arm 2 — output BEFORE the row exists. A `shell-output-delta` fires before
27
+ * the stream's `running` for its call. Pinned: nothing is lost — the enricher
28
+ * buffers the chunk and applies it once the row exists, so the final `result`
29
+ * carries both chunks in order. Predicted: NO move (the translator holds
30
+ * a delta for a call the stream has not announced and replays it after the
31
+ * `tool_started` that announces it).
32
+ *
33
+ * Arm 3 — the completion delta reports an ERROR, and a model event sits
34
+ * between it and the stream's own `error`. Pinned: the translator honours the
35
+ * delta's `result.status: "error"` — the row is FAILED from the
36
+ * instant the failure was observed (`completedAt` and, for a gated shell,
37
+ * `approvalRequestedAt` at the delta's own tick), and the stream's `error`
38
+ * event that follows supplies the text. Until #1097 (as this net first
39
+ * pinned it) the enricher promoted every completion delta to
40
+ * COMPLETED, the monotonic merge then refused the stream's FAILED, and the
41
+ * row ended COMPLETED carrying an `error` — a row that lied. Moved in #1097
42
+ * by one line this header had not named when the net was written:
43
+ * the failure text is `error` alone; and, as predicted, in the
44
+ * status and in `approvalRequestedAt`.
45
+ *
46
+ * Regenerate ONLY after a deliberate behavior change:
47
+ * npx vitest run src/activities/execute-cursor/__tests__/hermetic -u
48
+ */
49
+
50
+ import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
51
+ import { toJson } from "@bufbuild/protobuf";
52
+ import type { InteractionUpdate } from "@cursor/sdk";
53
+ import { AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
54
+ import { ExecutionPhase, ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
55
+
56
+ vi.mock("@cursor/sdk", async () =>
57
+ (await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSdkModule(),
58
+ );
59
+ vi.mock("@cursor/sdk/sqlite", async () =>
60
+ (await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSqliteModule(),
61
+ );
62
+ vi.mock("../../../../client/stigmer-client.js", async () =>
63
+ (await import("../../../../__test-utils__/hermetic-activity.js")).hermeticStigmerClientModule(),
64
+ );
65
+
66
+ import {
67
+ ScriptedClock,
68
+ createHermeticEnvironment,
69
+ type HermeticEnvironment,
70
+ } from "../../../../__test-utils__/hermetic-activity.js";
71
+ import { ScriptedCursorAgent, sdkEvents, step } from "../../__test-utils__/scripted-agent.js";
72
+ import {
73
+ FIXTURE,
74
+ SDK_CATALOG,
75
+ beginCursorScenario,
76
+ cursorExecutionRecord,
77
+ runCursorTurn,
78
+ } from "../../__test-utils__/hermetic-cursor.js";
79
+ import { stubRegistryFetch } from "../../../../__test-utils__/model-registry-fixture.js";
80
+
81
+ const USER_MESSAGE = "Run the test suite.";
82
+ const COMMAND = "npm test";
83
+ const SHELL_ARGS = { command: COMMAND };
84
+ const CHUNK_1 = "> test\n";
85
+ const CHUNK_2 = "12 passing\n";
86
+ const FULL_OUTPUT = CHUNK_1 + CHUNK_2;
87
+
88
+ /**
89
+ * The delta channel's shapes, typed against the SDK so a drift fails `tsc`
90
+ * (the stigmer#1053 dividend — writing these is how the runner learned the
91
+ * timing deltas carry `modelCallId`, the LLM call that issued the tool;
92
+ * nothing in the runner reads it yet).
93
+ */
94
+ const MODEL_CALL_ID = "model-call-hermetic-shelldelta";
95
+ const deltas = {
96
+ started(callId: string): InteractionUpdate {
97
+ return { type: "tool-call-started", callId, modelCallId: MODEL_CALL_ID, toolCall: { type: "shell", args: SHELL_ARGS } };
98
+ },
99
+ output(callId: string, data: string): InteractionUpdate {
100
+ return { type: "shell-output-delta", event: { callId, type: "stdout", data } };
101
+ },
102
+ completedOk(callId: string, stdout: string): InteractionUpdate {
103
+ return {
104
+ type: "tool-call-completed",
105
+ callId,
106
+ modelCallId: MODEL_CALL_ID,
107
+ toolCall: {
108
+ type: "shell",
109
+ args: SHELL_ARGS,
110
+ result: { status: "success", value: { exitCode: 0, signal: "", stdout, stderr: "", executionTime: 1_200 } },
111
+ },
112
+ };
113
+ },
114
+ completedError(callId: string, error: string): InteractionUpdate {
115
+ return {
116
+ type: "tool-call-completed",
117
+ callId,
118
+ modelCallId: MODEL_CALL_ID,
119
+ toolCall: { type: "shell", args: SHELL_ARGS, result: { status: "error", error } },
120
+ };
121
+ },
122
+ };
123
+
124
+ describe("ExecuteCursor hermetic — the delta channel on a shell row", () => {
125
+ let env: HermeticEnvironment;
126
+ let registry: ReturnType<typeof stubRegistryFetch>;
127
+ const clock = new ScriptedClock();
128
+
129
+ beforeAll(() => {
130
+ env = createHermeticEnvironment();
131
+ registry = stubRegistryFetch();
132
+ clock.install();
133
+ });
134
+
135
+ afterAll(() => {
136
+ clock.uninstall();
137
+ registry.restore();
138
+ env.dispose();
139
+ });
140
+
141
+ it("arm 1: started, output and completed deltas between the stream's running and completed fold onto one row", async () => {
142
+ const AGENT_ID = "agent-hermetic-shelldelta-0001";
143
+ const RUN_ID = "run-hermetic-shelldelta-0001";
144
+ const CALL_ID = "call-hermetic-shelldelta-0001";
145
+ const TEXT_AFTER = "All 12 tests pass.";
146
+ const ev = sdkEvents(AGENT_ID, RUN_ID);
147
+ const agent = new ScriptedCursorAgent({
148
+ agentId: AGENT_ID,
149
+ runIds: [RUN_ID],
150
+ observeStep: () => clock.tick(),
151
+ turns: [
152
+ [
153
+ step.event(ev.init()),
154
+ step.event(ev.assistant("Running the tests.")),
155
+ step.event(ev.toolCall(CALL_ID, "shell", "running", SHELL_ARGS)),
156
+ step.delta(deltas.started(CALL_ID)),
157
+ step.delta(deltas.output(CALL_ID, CHUNK_1)),
158
+ step.delta(deltas.output(CALL_ID, CHUNK_2)),
159
+ step.delta(deltas.completedOk(CALL_ID, FULL_OUTPUT)),
160
+ step.event(ev.toolCall(CALL_ID, "shell", "completed", SHELL_ARGS, FULL_OUTPUT)),
161
+ step.event(ev.assistant(TEXT_AFTER)),
162
+ step.turnEnded({ inputTokens: 2_000, outputTokens: 60, cacheReadTokens: 0, cacheWriteTokens: 0 }),
163
+ step.finished({ result: TEXT_AFTER, model: { id: FIXTURE.model, params: [] } }),
164
+ ],
165
+ ],
166
+ });
167
+ const record = cursorExecutionRecord({ message: USER_MESSAGE });
168
+ const scenario = beginCursorScenario({ env, clock, record, sdk: { agents: [agent], catalog: SDK_CATALOG } });
169
+
170
+ const invocation = await runCursorTurn(scenario);
171
+
172
+ expect(invocation.outcome.kind).toBe("returned");
173
+ expect(record.persistedPhases.at(-1)).toBe(ExecutionPhase.EXECUTION_COMPLETED);
174
+ const rows = record.toolCalls();
175
+ expect(rows, "the stream's two events and the four deltas fold into ONE row").toHaveLength(1);
176
+ const row = rows[0];
177
+ expect(row.status).toBe(ToolCallStatus.TOOL_CALL_COMPLETED);
178
+ expect(row.result, "the live output reached the row").toBe(FULL_OUTPUT);
179
+ expect(row.isStreaming, "finalize closed the OUTPUT stream").toBe(false);
180
+ expect(row.startedAt < row.completedAt).toBe(true);
181
+ expect(row.requiresApproval, "a shell is a gated built-in the hook never saw").toBe(true);
182
+ expect(row.approvalRequestedAt).toBe("");
183
+ expect(registry.urls.every((u) => u.includes("/model-registry"))).toBe(true);
184
+
185
+ const json = JSON.stringify(toJson(AgentExecutionStatusSchema, record.lastFullStatus!), null, 2) + "\n";
186
+ await expect(json).toMatchFileSnapshot("./goldens/shell-output-delta.status.json");
187
+ });
188
+
189
+ it("arm 2: an output delta that precedes the stream's running is held and lands once the row exists", async () => {
190
+ const AGENT_ID = "agent-hermetic-shelldelta-0002";
191
+ const RUN_ID = "run-hermetic-shelldelta-0002";
192
+ const CALL_ID = "call-hermetic-shelldelta-0002";
193
+ const TEXT_AFTER = "Done; the suite is green.";
194
+ const ev = sdkEvents(AGENT_ID, RUN_ID);
195
+ const agent = new ScriptedCursorAgent({
196
+ agentId: AGENT_ID,
197
+ runIds: [RUN_ID],
198
+ observeStep: () => clock.tick(),
199
+ turns: [
200
+ [
201
+ step.event(ev.init()),
202
+ step.event(ev.assistant("Running the tests.")),
203
+ step.delta(deltas.started(CALL_ID)),
204
+ step.delta(deltas.output(CALL_ID, CHUNK_1)),
205
+ step.event(ev.toolCall(CALL_ID, "shell", "running", SHELL_ARGS)),
206
+ step.delta(deltas.output(CALL_ID, CHUNK_2)),
207
+ step.delta(deltas.completedOk(CALL_ID, FULL_OUTPUT)),
208
+ step.event(ev.toolCall(CALL_ID, "shell", "completed", SHELL_ARGS, FULL_OUTPUT)),
209
+ step.event(ev.assistant(TEXT_AFTER)),
210
+ step.turnEnded({ inputTokens: 2_000, outputTokens: 60, cacheReadTokens: 0, cacheWriteTokens: 0 }),
211
+ step.finished({ result: TEXT_AFTER, model: { id: FIXTURE.model, params: [] } }),
212
+ ],
213
+ ],
214
+ });
215
+ const record = cursorExecutionRecord({ message: USER_MESSAGE });
216
+ const scenario = beginCursorScenario({ env, clock, record, sdk: { agents: [agent], catalog: SDK_CATALOG } });
217
+
218
+ await runCursorTurn(scenario);
219
+
220
+ expect(record.persistedPhases.at(-1)).toBe(ExecutionPhase.EXECUTION_COMPLETED);
221
+ const rows = record.toolCalls();
222
+ expect(rows).toHaveLength(1);
223
+ expect(rows[0].status).toBe(ToolCallStatus.TOOL_CALL_COMPLETED);
224
+ expect(rows[0].result, "the early chunk was not lost").toBe(FULL_OUTPUT);
225
+
226
+ const json = JSON.stringify(toJson(AgentExecutionStatusSchema, record.lastFullStatus!), null, 2) + "\n";
227
+ await expect(json).toMatchFileSnapshot("./goldens/shell-output-delta.output-first.status.json");
228
+ });
229
+
230
+ it("arm 3: an error-status completion delta, with a model event before the stream's error, fails the row from the instant it was observed", async () => {
231
+ const AGENT_ID = "agent-hermetic-shelldelta-0003";
232
+ const RUN_ID = "run-hermetic-shelldelta-0003";
233
+ const CALL_ID = "call-hermetic-shelldelta-0003";
234
+ const SHELL_ERROR = "sh: npm: command not found";
235
+ const TEXT_AFTER = "npm is not installed here.";
236
+ const ev = sdkEvents(AGENT_ID, RUN_ID);
237
+ const agent = new ScriptedCursorAgent({
238
+ agentId: AGENT_ID,
239
+ runIds: [RUN_ID],
240
+ observeStep: () => clock.tick(),
241
+ turns: [
242
+ [
243
+ step.event(ev.init()),
244
+ step.event(ev.assistant("Running the tests.")),
245
+ step.event(ev.toolCall(CALL_ID, "shell", "running", SHELL_ARGS)),
246
+ step.delta(deltas.started(CALL_ID)),
247
+ step.delta(deltas.completedError(CALL_ID, SHELL_ERROR)),
248
+ // The model reacts before the stream reports the tool's own outcome —
249
+ // the interleaving that lets a completion delta settle the row first.
250
+ step.event(ev.thinking("The command failed; npm may be missing.")),
251
+ step.event(ev.toolCall(CALL_ID, "shell", "error", SHELL_ARGS, SHELL_ERROR)),
252
+ step.event(ev.assistant(TEXT_AFTER)),
253
+ step.turnEnded({ inputTokens: 2_000, outputTokens: 80, cacheReadTokens: 0, cacheWriteTokens: 0 }),
254
+ step.finished({ result: TEXT_AFTER, model: { id: FIXTURE.model, params: [] } }),
255
+ ],
256
+ ],
257
+ });
258
+ const record = cursorExecutionRecord({ message: USER_MESSAGE });
259
+ const scenario = beginCursorScenario({ env, clock, record, sdk: { agents: [agent], catalog: SDK_CATALOG } });
260
+
261
+ await runCursorTurn(scenario);
262
+
263
+ expect(record.persistedPhases.at(-1)).toBe(ExecutionPhase.EXECUTION_COMPLETED);
264
+ const rows = record.toolCalls();
265
+ expect(rows).toHaveLength(1);
266
+ const row = rows[0];
267
+ // The delta said the tool failed; the row says so from that instant.
268
+ expect(row.status).toBe(ToolCallStatus.TOOL_CALL_FAILED);
269
+ expect(row.error, "the stream's error event supplied the text").toBe(SHELL_ERROR);
270
+ expect(row.result).toBe("");
271
+ expect(row.approvalRequestedAt, "a gated shell's gate stamp shares the observed instant").toBe(row.completedAt);
272
+
273
+ const json = JSON.stringify(toJson(AgentExecutionStatusSchema, record.lastFullStatus!), null, 2) + "\n";
274
+ await expect(json).toMatchFileSnapshot("./goldens/shell-output-delta.error-delta.status.json");
275
+ });
276
+ });
@@ -32,17 +32,17 @@
32
32
  * is the one point a scenario can rely on: the STOP is keyed on the
33
33
  * persisted status's CONTENT (the COMPLETED row), not on which persist
34
34
  * happens to carry it, because a tool-call transition force-flushes
35
- * (`contentDirty`) whatever the cadence says. (Until S3 M5 the scheduler
35
+ * (the builder's `dirty` flag) whatever the cadence says. (Until #1096 the scheduler
36
36
  * paced text-only persists on REAL `performance.now()` time; the scripted
37
- * clock fakes it since Q-M5-7, so every persist is deterministic now.)
37
+ * clock fakes it since then, so every persist is deterministic now.)
38
38
  *
39
- * Engine disposition and cancellation since S2 M3 (entry 20260911.03): the
40
- * adapter cancels the SDK run on EVERY stop (Q-M3-4; before, a platform stop
39
+ * Engine disposition and cancellation since #1070: the
40
+ * adapter cancels the SDK run on EVERY stop (before, a platform stop
41
41
  * broke the loop and left the run executing) and parks the handle on every
42
- * non-failed exit (Q-S2-6; before, a stall dropped it — the adapter cannot
42
+ * non-failed exit (before, a stall dropped it — the adapter cannot
43
43
  * tell a stall from a cost cap, and a wedged parked handle is caught by the
44
44
  * poisoned-handle recovery on the next turn). The two assertions that moved
45
- * say so on their line. The cost-cap golden was regenerated at M3b with a
45
+ * say so on their line. The cost-cap golden was regenerated in #1070 with a
46
46
  * timestamp-only diff (every terminal stamp one scripted second earlier):
47
47
  * the run is now cancelled the instant the signal aborts, before the SDK
48
48
  * double pulls — and the clock ticks on — one more step.
@@ -188,7 +188,7 @@ describe("ExecuteCursor hermetic — the stream loop's self-stop arms", () => {
188
188
  // ── Assert: engine disposition ───────────────────────────────────────────
189
189
  expect(agent.runs[0].cancelCalls, "the runtime's stop cancelled the run once").toHaveLength(1);
190
190
  expect(agent.closeCalls, "the handle is not closed").toBe(0);
191
- // Q-S2-6 (S2 M3): parked on every non-failed exit; before M3 a stall dropped it.
191
+ // Since #1070: parked on every non-failed exit; before, a stall dropped it.
192
192
  expect(_parkedAgentCountForTests(), "parked for the session's next turn").toBe(1);
193
193
  expect(record.sessionUpdates).toHaveLength(1);
194
194
 
@@ -318,7 +318,7 @@ describe("ExecuteCursor hermetic — the stream loop's self-stop arms", () => {
318
318
  expect(final.messages.some((m) => m.content === NEVER_SEEN), "the event after the STOP is never processed").toBe(false);
319
319
 
320
320
  // ── Assert: engine disposition ───────────────────────────────────────────
321
- // Q-M3-4 (S2 M3): the SDK run is cancelled on every stop; before M3 a
321
+ // Since #1070: the SDK run is cancelled on every stop; before, a
322
322
  // platform stop broke the loop and left the run executing behind the
323
323
  // parked handle.
324
324
  expect(agent.runs[0].cancelCalls, "the runtime's stop cancelled the run once").toHaveLength(1);