@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,196 @@
1
+ /**
2
+ * Hermetic golden: SUB-AGENT DELEGATION on the Cursor harness — the root agent
3
+ * hands work to a sub-agent through the SDK's `task` tool, and the sub-agent's
4
+ * own conversation arrives, whole, in the `task` call's result.
5
+ *
6
+ * Invariant pinned: the translator opens a sub-agent for every
7
+ * `tool_call` named `task` (`sub_agent_started` before the row's own start) as
8
+ * well as writing the row to the root transcript. The `running` event opens a `SubAgentExecution` keyed by the
9
+ * task call id (`name` from `subagentType`, `subject` from `description`,
10
+ * `input` from `prompt`, IN_PROGRESS); the `completed` event closes it
11
+ * COMPLETED with `output` (the stringified result) and rebuilds its transcript
12
+ * from the result's `conversationSteps` (`sub-agent-steps.ts`): an
13
+ * `assistantMessage` step is an AI row, and a `toolCall` step is a tool row on
14
+ * the transcript's LAST AI message — the assistant step that proposed it — named
15
+ * from its `<kind>ToolCall` key (`buildSubAgentToolCall`), with the SDK's
16
+ * `toolCallId` as its id, its status from the `result` oneof, both timestamps,
17
+ * `args` and `argsPreview`; a tool step with no assistant step before it gets
18
+ * an empty AI message of its own, the root transcript's rule. The root
19
+ * transcript carries the `task` row itself (COMPLETED, `result` = the same
20
+ * stringified object) on the message that proposed it. This is Cursor's
21
+ * timing — the sub-agent's rows exist only at completion — and stays Cursor's.
22
+ *
23
+ * Moved 2026-09-14 (#1097), the ONE hunk this golden was
24
+ * predicted to take: the sub-agent's `read` row sits on the AI message of the
25
+ * assistant step that precedes it (`messages[0]`, "Looking at README.md."),
26
+ * and the `content: ""` message that carried it until then (`messages[1]`) is
27
+ * gone — the canonical builder attaches a tool row to its scope's current AI
28
+ * message, the shape native's sub-agent transcripts took in #1096, and the
29
+ * accumulator's steps extractor was aligned before the swap to the shared
30
+ * builder so the swap moved nothing.
31
+ *
32
+ * On the record as found (#1134): the `task` row's `result` and the
33
+ * sub-agent's `output` are two copies of one stringified object.
34
+ *
35
+ * Why this net exists: none of the seventeen earlier Cursor goldens carried
36
+ * a sub-agent row, and #1097 deleted the transcript-rebuild whole.
37
+ *
38
+ * Regenerate ONLY after a deliberate behavior change:
39
+ * npx vitest run src/activities/execute-cursor/__tests__/hermetic -u
40
+ */
41
+
42
+ import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
43
+ import { toJson } from "@bufbuild/protobuf";
44
+ import { AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
45
+ import {
46
+ ExecutionPhase,
47
+ MessageType,
48
+ SubAgentStatus,
49
+ ToolCallStatus,
50
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
51
+
52
+ vi.mock("@cursor/sdk", async () =>
53
+ (await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSdkModule(),
54
+ );
55
+ vi.mock("../../../../client/stigmer-client.js", async () =>
56
+ (await import("../../../../__test-utils__/hermetic-activity.js")).hermeticStigmerClientModule(),
57
+ );
58
+
59
+ import {
60
+ ScriptedClock,
61
+ createHermeticEnvironment,
62
+ type HermeticEnvironment,
63
+ } from "../../../../__test-utils__/hermetic-activity.js";
64
+ import { ScriptedCursorAgent, sdkEvents, step } from "../../__test-utils__/scripted-agent.js";
65
+ import {
66
+ FIXTURE,
67
+ SDK_CATALOG,
68
+ beginCursorScenario,
69
+ cursorExecutionRecord,
70
+ runCursorTurn,
71
+ } from "../../__test-utils__/hermetic-cursor.js";
72
+ import { stubRegistryFetch } from "../../../../__test-utils__/model-registry-fixture.js";
73
+
74
+ const AGENT_ID = "agent-hermetic-subagent-0001";
75
+ const RUN_ID = "run-hermetic-subagent-0001";
76
+ const TASK_CALL_ID = "call-hermetic-task-0001";
77
+ const SUB_READ_CALL_ID = "call-hermetic-sub-read-0001";
78
+ const USER_MESSAGE = "Ask the helper what README.md says.";
79
+ const ROOT_OPENING = "Delegating to the helper.";
80
+ const TASK_ARGS = {
81
+ subagentType: "helper",
82
+ description: "Read README.md and report its content.",
83
+ prompt: "Read README.md and reply with its content in one line.",
84
+ };
85
+ const HELPER_OPENING = "Looking at README.md.";
86
+ const HELPER_READ_ARGS = { path: "README.md" };
87
+ const HELPER_READ_RESULT = "# Hermetic\n\nA fixture readme.\n";
88
+ const HELPER_ANSWER = "README.md is a one-line fixture description.";
89
+ /** The SDK's task result: the sub-agent's conversation as protobuf-oneof JSON steps. */
90
+ const TASK_RESULT = {
91
+ conversationSteps: [
92
+ { type: "assistantMessage", message: { text: HELPER_OPENING } },
93
+ {
94
+ toolCall: {
95
+ toolCallId: SUB_READ_CALL_ID,
96
+ readToolCall: { args: HELPER_READ_ARGS, result: { success: { content: HELPER_READ_RESULT } } },
97
+ },
98
+ },
99
+ { type: "assistantMessage", message: { text: HELPER_ANSWER } },
100
+ ],
101
+ };
102
+ const ROOT_CLOSING = "The helper reports: README.md is a one-line fixture description.";
103
+
104
+ describe("ExecuteCursor hermetic — sub-agent delegation", () => {
105
+ let env: HermeticEnvironment;
106
+ let registry: ReturnType<typeof stubRegistryFetch>;
107
+ const clock = new ScriptedClock();
108
+
109
+ beforeAll(() => {
110
+ env = createHermeticEnvironment();
111
+ registry = stubRegistryFetch();
112
+ clock.install();
113
+ });
114
+
115
+ afterAll(() => {
116
+ clock.uninstall();
117
+ registry.restore();
118
+ env.dispose();
119
+ });
120
+
121
+ it("tracks the task as a SubAgentExecution keyed by the call id and rebuilds its transcript at completion", async () => {
122
+ // ── Arrange ──────────────────────────────────────────────────────────────
123
+ const ev = sdkEvents(AGENT_ID, RUN_ID);
124
+ const agent = new ScriptedCursorAgent({
125
+ agentId: AGENT_ID,
126
+ runIds: [RUN_ID],
127
+ observeStep: () => clock.tick(),
128
+ turns: [
129
+ [
130
+ step.event(ev.init()),
131
+ step.event(ev.assistant(ROOT_OPENING)),
132
+ step.event(ev.toolCall(TASK_CALL_ID, "task", "running", TASK_ARGS)),
133
+ step.event(ev.toolCall(TASK_CALL_ID, "task", "completed", TASK_ARGS, TASK_RESULT)),
134
+ step.event(ev.assistant(ROOT_CLOSING)),
135
+ step.turnEnded({ inputTokens: 3_900, outputTokens: 102, cacheReadTokens: 0, cacheWriteTokens: 0 }),
136
+ step.finished({ result: ROOT_CLOSING, model: { id: FIXTURE.model, params: [] } }),
137
+ ],
138
+ ],
139
+ });
140
+ const record = cursorExecutionRecord({ message: USER_MESSAGE });
141
+ const scenario = beginCursorScenario({
142
+ env,
143
+ clock,
144
+ record,
145
+ sdk: { agents: [agent], catalog: SDK_CATALOG },
146
+ });
147
+
148
+ // ── Act ──────────────────────────────────────────────────────────────────
149
+ const invocation = await runCursorTurn(scenario);
150
+
151
+ // ── Assert: outcome ──────────────────────────────────────────────────────
152
+ expect(invocation.outcome.kind).toBe("returned");
153
+ expect((invocation.outcome as { value: Record<string, unknown> }).value.phase).toBe("EXECUTION_COMPLETED");
154
+ expect(record.persistedPhases.at(-1)).toBe(ExecutionPhase.EXECUTION_COMPLETED);
155
+
156
+ // ── Assert: the root transcript ──────────────────────────────────────────
157
+ const final = record.lastFullStatus!;
158
+ expect(record.toolCalls().map((tc) => [tc.id, tc.name, tc.status])).toEqual([
159
+ [TASK_CALL_ID, "task", ToolCallStatus.TOOL_CALL_COMPLETED],
160
+ ]);
161
+ expect(final.messages.map((m) => [m.type, m.content, m.toolCalls.map((tc) => tc.id)])).toEqual([
162
+ [MessageType.MESSAGE_AI, ROOT_OPENING, [TASK_CALL_ID]],
163
+ [MessageType.MESSAGE_AI, ROOT_CLOSING, []],
164
+ ]);
165
+
166
+ // ── Assert: the sub-agent execution ──────────────────────────────────────
167
+ expect(final.subAgentExecutions).toHaveLength(1);
168
+ const sub = final.subAgentExecutions[0];
169
+ expect(sub.id, "keyed by the task call id").toBe(TASK_CALL_ID);
170
+ expect(sub.name).toBe("helper");
171
+ expect(sub.subject).toBe(TASK_ARGS.description);
172
+ expect(sub.input).toBe(TASK_ARGS.prompt);
173
+ expect(sub.status).toBe(SubAgentStatus.SUB_AGENT_COMPLETED);
174
+ expect(sub.startedAt < sub.completedAt).toBe(true);
175
+ expect(sub.output, "the stringified task result").toBe(JSON.stringify(TASK_RESULT));
176
+
177
+ // The rebuilt transcript: the tool step joins the assistant step that
178
+ // proposed it, the root transcript's own boundary rule.
179
+ expect(sub.messages.map((m) => [m.type, m.content, m.toolCalls.map((tc) => tc.id)])).toEqual([
180
+ [MessageType.MESSAGE_AI, HELPER_OPENING, [SUB_READ_CALL_ID]],
181
+ [MessageType.MESSAGE_AI, HELPER_ANSWER, []],
182
+ ]);
183
+ const subRead = sub.messages[0].toolCalls[0];
184
+ expect(subRead.name, "the bare tool name from the readToolCall key").toBe("read");
185
+ expect(subRead.status).toBe(ToolCallStatus.TOOL_CALL_COMPLETED);
186
+ expect(subRead.args).toEqual(HELPER_READ_ARGS);
187
+ expect(subRead.result).toBe(JSON.stringify({ content: HELPER_READ_RESULT }));
188
+
189
+ // ── Assert: hermeticity ──────────────────────────────────────────────────
190
+ expect(registry.urls.every((u) => u.includes("/model-registry"))).toBe(true);
191
+
192
+ // ── Assert: the golden ───────────────────────────────────────────────────
193
+ const json = JSON.stringify(toJson(AgentExecutionStatusSchema, final), null, 2) + "\n";
194
+ await expect(json).toMatchFileSnapshot("./goldens/sub-agent-delegation.status.json");
195
+ });
196
+ });
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Hermetic golden: a turn with MODEL THINKING on both sides of a tool call,
3
+ * through the whole `ExecuteCursor` activity.
4
+ *
5
+ * Invariant pinned (the rule the canonical builder had to reproduce when it
6
+ * took over in #1097): the Cursor SDK has ONE `run_id` per `send()`, so the transcript's
7
+ * segmentation is not by run but by tool call — a `tool_call` event closes the
8
+ * run's streaming AI and THINKING rows (the translator's `message_finish` for
9
+ * the open segment; until #1097 the accumulator's own finalize on a tool call),
10
+ * and the thinking or text that follows opens NEW rows. Hence the shape:
11
+ * THINKING(T1), AI(A1 + the read row), THINKING(T2), AI(A2). The read row lands
12
+ * on A1 (the last AI message by backward scan; a THINKING row is skipped), and
13
+ * no row is left `isStreaming` when the turn ends.
14
+ *
15
+ * Predicted for the swap to the shared builder (2026-09-14): NO move.
16
+ * The builder keeps one THINKING row per segment on Cursor (the translator
17
+ * mints a segment id per text-or-thinking run between tool calls) and keeps
18
+ * the tool on the message that proposed it. A diff in this golden is a
19
+ * pause, not a regeneration.
20
+ *
21
+ * Why this net exists: none of the seventeen earlier Cursor goldens carried
22
+ * a THINKING row, and the thinking rule is one #1097 rewrote.
23
+ *
24
+ * Regenerate ONLY after a deliberate behavior change:
25
+ * npx vitest run src/activities/execute-cursor/__tests__/hermetic -u
26
+ */
27
+
28
+ import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
29
+ import { toJson } from "@bufbuild/protobuf";
30
+ import { AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
31
+ import { ExecutionPhase, MessageType, ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
32
+
33
+ vi.mock("@cursor/sdk", async () =>
34
+ (await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSdkModule(),
35
+ );
36
+ vi.mock("../../../../client/stigmer-client.js", async () =>
37
+ (await import("../../../../__test-utils__/hermetic-activity.js")).hermeticStigmerClientModule(),
38
+ );
39
+
40
+ import {
41
+ ScriptedClock,
42
+ createHermeticEnvironment,
43
+ type HermeticEnvironment,
44
+ } from "../../../../__test-utils__/hermetic-activity.js";
45
+ import { ScriptedCursorAgent, sdkEvents, step } from "../../__test-utils__/scripted-agent.js";
46
+ import {
47
+ FIXTURE,
48
+ SDK_CATALOG,
49
+ beginCursorScenario,
50
+ cursorExecutionRecord,
51
+ runCursorTurn,
52
+ } from "../../__test-utils__/hermetic-cursor.js";
53
+ import { stubRegistryFetch } from "../../../../__test-utils__/model-registry-fixture.js";
54
+
55
+ const AGENT_ID = "agent-hermetic-thinking-0001";
56
+ const RUN_ID = "run-hermetic-thinking-0001";
57
+ const CALL_ID = "call-hermetic-thinking-read-0001";
58
+ const USER_MESSAGE = "Summarise README.md.";
59
+ const THINKING_BEFORE = "The user wants a summary; I should read the file first.";
60
+ const TEXT_BEFORE = "Reading the file.";
61
+ const READ_ARGS = { path: "README.md" };
62
+ const READ_RESULT = "# Hermetic\n\nA fixture readme.\n";
63
+ const THINKING_AFTER = "One line of content; a one-sentence summary will do.";
64
+ const TEXT_AFTER = "README.md is a one-line fixture description.";
65
+
66
+ describe("ExecuteCursor hermetic — thinking on both sides of a tool call", () => {
67
+ let env: HermeticEnvironment;
68
+ let registry: ReturnType<typeof stubRegistryFetch>;
69
+ const clock = new ScriptedClock();
70
+
71
+ beforeAll(() => {
72
+ env = createHermeticEnvironment();
73
+ registry = stubRegistryFetch();
74
+ clock.install();
75
+ });
76
+
77
+ afterAll(() => {
78
+ clock.uninstall();
79
+ registry.restore();
80
+ env.dispose();
81
+ });
82
+
83
+ it("folds into THINKING, AI+row, THINKING, AI with nothing left streaming and completes", async () => {
84
+ // ── Arrange ──────────────────────────────────────────────────────────────
85
+ const ev = sdkEvents(AGENT_ID, RUN_ID);
86
+ const agent = new ScriptedCursorAgent({
87
+ agentId: AGENT_ID,
88
+ runIds: [RUN_ID],
89
+ observeStep: () => clock.tick(),
90
+ turns: [
91
+ [
92
+ step.event(ev.init()),
93
+ step.event(ev.thinking(THINKING_BEFORE)),
94
+ step.event(ev.assistant(TEXT_BEFORE)),
95
+ step.event(ev.toolCall(CALL_ID, "read", "running", READ_ARGS)),
96
+ step.event(ev.toolCall(CALL_ID, "read", "completed", READ_ARGS, READ_RESULT)),
97
+ step.event(ev.thinking(THINKING_AFTER)),
98
+ step.event(ev.assistant(TEXT_AFTER)),
99
+ step.turnEnded({ inputTokens: 2_400, outputTokens: 140, cacheReadTokens: 0, cacheWriteTokens: 0 }),
100
+ step.finished({ result: TEXT_AFTER, model: { id: FIXTURE.model, params: [] } }),
101
+ ],
102
+ ],
103
+ });
104
+ const record = cursorExecutionRecord({ message: USER_MESSAGE });
105
+ const scenario = beginCursorScenario({
106
+ env,
107
+ clock,
108
+ record,
109
+ sdk: { agents: [agent], catalog: SDK_CATALOG },
110
+ });
111
+
112
+ // ── Act ──────────────────────────────────────────────────────────────────
113
+ const invocation = await runCursorTurn(scenario);
114
+
115
+ // ── Assert: outcome ──────────────────────────────────────────────────────
116
+ expect(invocation.outcome.kind).toBe("returned");
117
+ expect((invocation.outcome as { value: Record<string, unknown> }).value.phase).toBe("EXECUTION_COMPLETED");
118
+ expect(record.persistedPhases.at(-1)).toBe(ExecutionPhase.EXECUTION_COMPLETED);
119
+
120
+ // ── Assert: the segmentation ─────────────────────────────────────────────
121
+ const final = record.lastFullStatus!;
122
+ expect(
123
+ final.messages.map((m) => [m.type, m.content]),
124
+ "a tool call closes the run's THINKING and AI rows; what follows opens new ones",
125
+ ).toEqual([
126
+ [MessageType.MESSAGE_THINKING, THINKING_BEFORE],
127
+ [MessageType.MESSAGE_AI, TEXT_BEFORE],
128
+ [MessageType.MESSAGE_THINKING, THINKING_AFTER],
129
+ [MessageType.MESSAGE_AI, TEXT_AFTER],
130
+ ]);
131
+ expect(final.messages.every((m) => !m.isStreaming), "finalize clears every streaming flag").toBe(true);
132
+
133
+ // ── Assert: the row sits on the text that proposed it ────────────────────
134
+ const rows = record.toolCalls();
135
+ expect(rows.map((tc) => [tc.id, tc.status])).toEqual([[CALL_ID, ToolCallStatus.TOOL_CALL_COMPLETED]]);
136
+ expect(final.messages[1].toolCalls.map((tc) => tc.id), "the read row is on AI(A1), not on a THINKING row").toEqual([CALL_ID]);
137
+
138
+ // ── Assert: hermeticity ──────────────────────────────────────────────────
139
+ expect(registry.urls.every((u) => u.includes("/model-registry"))).toBe(true);
140
+
141
+ // ── Assert: the golden ───────────────────────────────────────────────────
142
+ const json = JSON.stringify(toJson(AgentExecutionStatusSchema, final), null, 2) + "\n";
143
+ await expect(json).toMatchFileSnapshot("./goldens/thinking-turn.status.json");
144
+ });
145
+ });
@@ -28,7 +28,7 @@
28
28
  * plane ever sees for these executions is EXECUTION_FAILED — `persistedPhases`
29
29
  * is `[FAILED]`, not `[IN_PROGRESS, FAILED]`.
30
30
  *
31
- * Golden hunk since S3 M4 (Q-M4-7, ruled Q-M4-12 A): `sdk-error-at-create`
31
+ * Golden hunk since #1096: `sdk-error-at-create`
32
32
  * carries an EMPTY `fileChangeProgress` (`changeSetId`, `capturedAt`, no
33
33
  * entries). The runtime refreshes the strip on every write, and this turn's
34
34
  * FAILED write is its first write in capture mode (the hermetic environment
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Hermetic golden: the agent's TO-DO LIST — two `updateTodos` tool calls, the
3
+ * second a `merge`, through the whole `ExecuteCursor` activity.
4
+ *
5
+ * Invariant pinned: a todo tool call is a row like any other AND a projection.
6
+ * The shared builder projects a COMPLETED `ToolKind.TODO` row's `args.todos`
7
+ * into `status.todos` through the shared `applyTodoUpdate` — a full replace by
8
+ * default, a MERGE when the SDK's args say `merge: true` (the first write's
9
+ * `createdAt` survives, `updatedAt` moves) — and the row stays on the message
10
+ * that proposed it: an `updateTodos`
11
+ * row (COMPLETED, `toolKind` TODO, `args`, `argsPreview`, `result`) on
12
+ * `messages[0]` and another on `messages[1]`. So: three AI messages, two
13
+ * rows, two todos. The web console hides the row (`isInternalTool`); the CLI
14
+ * TUI shows it, as it does for native.
15
+ *
16
+ * Moved 2026-09-14 (#1097), the TWO hunks this golden was
17
+ * predicted to take: until then the accumulator DROPPED the row (a suppressed-
18
+ * tool-names set) and the transcript showed three AI messages with
19
+ * no rows — a per-harness branch on a tool name the canonical builder does
20
+ * not have (native has always kept its `write_todos` row). The accumulator
21
+ * was aligned before the swap to the shared builder so the swap moved nothing;
22
+ * `todos` was and is byte-identical. The todo tracker went at the swap, where
23
+ * the builder took over projecting the todos from the row.
24
+ *
25
+ * Why this net exists: no earlier Cursor golden carried a todo.
26
+ *
27
+ * Regenerate ONLY after a deliberate behavior change:
28
+ * npx vitest run src/activities/execute-cursor/__tests__/hermetic -u
29
+ */
30
+
31
+ import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
32
+ import { toJson } from "@bufbuild/protobuf";
33
+ import { AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
34
+ import { ExecutionPhase, MessageType, TodoStatus, ToolCallStatus, ToolKind } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
35
+
36
+ vi.mock("@cursor/sdk", async () =>
37
+ (await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSdkModule(),
38
+ );
39
+ vi.mock("../../../../client/stigmer-client.js", async () =>
40
+ (await import("../../../../__test-utils__/hermetic-activity.js")).hermeticStigmerClientModule(),
41
+ );
42
+
43
+ import {
44
+ ScriptedClock,
45
+ createHermeticEnvironment,
46
+ type HermeticEnvironment,
47
+ } from "../../../../__test-utils__/hermetic-activity.js";
48
+ import { ScriptedCursorAgent, sdkEvents, step } from "../../__test-utils__/scripted-agent.js";
49
+ import {
50
+ FIXTURE,
51
+ SDK_CATALOG,
52
+ beginCursorScenario,
53
+ cursorExecutionRecord,
54
+ runCursorTurn,
55
+ } from "../../__test-utils__/hermetic-cursor.js";
56
+ import { stubRegistryFetch } from "../../../../__test-utils__/model-registry-fixture.js";
57
+
58
+ const AGENT_ID = "agent-hermetic-todo-0001";
59
+ const RUN_ID = "run-hermetic-todo-0001";
60
+ const FIRST_CALL_ID = "call-hermetic-todo-0001";
61
+ const SECOND_CALL_ID = "call-hermetic-todo-0002";
62
+ const USER_MESSAGE = "Plan the two steps, then do the first.";
63
+ const TEXT_PLAN = "Two steps; writing them down.";
64
+ /** The current SDK's `updateTodos` shape: camelCase statuses, no per-item id. */
65
+ const FIRST_WRITE = {
66
+ todos: [
67
+ { content: "Read the fixture", status: "pending" },
68
+ { content: "Summarise it", status: "pending" },
69
+ ],
70
+ };
71
+ const TEXT_WORK = "First step done.";
72
+ const SECOND_WRITE = {
73
+ todos: [{ content: "Read the fixture", status: "completed" }],
74
+ merge: true,
75
+ };
76
+ const TEXT_CLOSING = "The first step is complete; the second is pending.";
77
+
78
+ describe("ExecuteCursor hermetic — todo writes", () => {
79
+ let env: HermeticEnvironment;
80
+ let registry: ReturnType<typeof stubRegistryFetch>;
81
+ const clock = new ScriptedClock();
82
+
83
+ beforeAll(() => {
84
+ env = createHermeticEnvironment();
85
+ registry = stubRegistryFetch();
86
+ clock.install();
87
+ });
88
+
89
+ afterAll(() => {
90
+ clock.uninstall();
91
+ registry.restore();
92
+ env.dispose();
93
+ });
94
+
95
+ it("projects a replace then a merge into status.todos and keeps a row per write in the transcript", async () => {
96
+ // ── Arrange ──────────────────────────────────────────────────────────────
97
+ const ev = sdkEvents(AGENT_ID, RUN_ID);
98
+ const agent = new ScriptedCursorAgent({
99
+ agentId: AGENT_ID,
100
+ runIds: [RUN_ID],
101
+ observeStep: () => clock.tick(),
102
+ turns: [
103
+ [
104
+ step.event(ev.init()),
105
+ step.event(ev.assistant(TEXT_PLAN)),
106
+ step.event(ev.toolCall(FIRST_CALL_ID, "updateTodos", "running", FIRST_WRITE)),
107
+ step.event(ev.toolCall(FIRST_CALL_ID, "updateTodos", "completed", FIRST_WRITE, "ok")),
108
+ step.event(ev.assistant(TEXT_WORK)),
109
+ step.event(ev.toolCall(SECOND_CALL_ID, "updateTodos", "running", SECOND_WRITE)),
110
+ step.event(ev.toolCall(SECOND_CALL_ID, "updateTodos", "completed", SECOND_WRITE, "ok")),
111
+ step.event(ev.assistant(TEXT_CLOSING)),
112
+ step.turnEnded({ inputTokens: 2_600, outputTokens: 160, cacheReadTokens: 0, cacheWriteTokens: 0 }),
113
+ step.finished({ result: TEXT_CLOSING, model: { id: FIXTURE.model, params: [] } }),
114
+ ],
115
+ ],
116
+ });
117
+ const record = cursorExecutionRecord({ message: USER_MESSAGE });
118
+ const scenario = beginCursorScenario({
119
+ env,
120
+ clock,
121
+ record,
122
+ sdk: { agents: [agent], catalog: SDK_CATALOG },
123
+ });
124
+
125
+ // ── Act ──────────────────────────────────────────────────────────────────
126
+ const invocation = await runCursorTurn(scenario);
127
+
128
+ // ── Assert: outcome ──────────────────────────────────────────────────────
129
+ expect(invocation.outcome.kind).toBe("returned");
130
+ expect((invocation.outcome as { value: Record<string, unknown> }).value.phase).toBe("EXECUTION_COMPLETED");
131
+ expect(record.persistedPhases.at(-1)).toBe(ExecutionPhase.EXECUTION_COMPLETED);
132
+
133
+ // ── Assert: the transcript — a row per write, on the message that proposed it ──
134
+ const final = record.lastFullStatus!;
135
+ expect(
136
+ final.messages.map((m) => [m.type, m.content, m.toolCalls.length]),
137
+ "the todo call splits the text like any tool, and its row stays",
138
+ ).toEqual([
139
+ [MessageType.MESSAGE_AI, TEXT_PLAN, 1],
140
+ [MessageType.MESSAGE_AI, TEXT_WORK, 1],
141
+ [MessageType.MESSAGE_AI, TEXT_CLOSING, 0],
142
+ ]);
143
+ const rows = record.toolCalls();
144
+ expect(rows.map((tc) => [tc.id, tc.toolKind, tc.status])).toEqual([
145
+ [FIRST_CALL_ID, ToolKind.TODO, ToolCallStatus.TOOL_CALL_COMPLETED],
146
+ [SECOND_CALL_ID, ToolKind.TODO, ToolCallStatus.TOOL_CALL_COMPLETED],
147
+ ]);
148
+
149
+ // ── Assert: the todos, by key (byte-identical across the swap) ──────────
150
+ expect(Object.keys(final.todos).sort()).toEqual(["todo-0", "todo-1"]);
151
+ const first = final.todos["todo-0"];
152
+ const second = final.todos["todo-1"];
153
+ expect([first.content, first.status]).toEqual(["Read the fixture", TodoStatus.TODO_COMPLETED]);
154
+ expect(first.createdAt < first.updatedAt, "the merge kept the first write's createdAt and moved updatedAt").toBe(true);
155
+ expect([second.content, second.status]).toEqual(["Summarise it", TodoStatus.TODO_PENDING]);
156
+ expect(second.createdAt, "untouched by the merge").toBe(second.updatedAt);
157
+
158
+ // ── Assert: hermeticity ──────────────────────────────────────────────────
159
+ expect(registry.urls.every((u) => u.includes("/model-registry"))).toBe(true);
160
+
161
+ // ── Assert: the golden ───────────────────────────────────────────────────
162
+ const json = JSON.stringify(toJson(AgentExecutionStatusSchema, final), null, 2) + "\n";
163
+ await expect(json).toMatchFileSnapshot("./goldens/todo-write.status.json");
164
+ });
165
+ });
@@ -8,11 +8,11 @@
8
8
  * event's args, `result` from the completed event, `startedAt`/`completedAt`
9
9
  * from the two events' instants, `toolKind` classified, no approval fields set
10
10
  * (a read-only built-in is not gated) — and the turn ends COMPLETED. The golden
11
- * (`goldens/tool-call.status.json`) is the row shape S4's canonical transcript
12
- * builder must reproduce byte for byte.
11
+ * (`goldens/tool-call.status.json`) is the row shape the canonical transcript
12
+ * builder (#1097) must reproduce byte for byte.
13
13
  *
14
14
  * Parent phase rows exercised beyond `plain-turn`: run the turn and consume
15
- * the engine stream (tool-call folding in `message-translator.ts`); the turn
15
+ * the engine stream (`translator.ts` into the shared `TranscriptBuilder`); the turn
16
16
  * boundary with nothing to gate or capture (a read tool writes no file; the
17
17
  * per-session workspace is unchanged, so the capture finds no candidate).
18
18
  *