@stigmer/runner 3.15.3-dev.20260914100347 → 3.15.3-dev.20260916211208

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 (549) hide show
  1. package/README.md +1 -0
  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 +14 -11
  12. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js.map +1 -1
  13. package/dist/activities/execute-cursor/__test-utils__/fold.d.ts +61 -0
  14. package/dist/activities/execute-cursor/__test-utils__/fold.js +94 -0
  15. package/dist/activities/execute-cursor/__test-utils__/fold.js.map +1 -0
  16. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js +1 -1
  17. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js.map +1 -1
  18. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +52 -14
  19. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +46 -12
  20. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
  21. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.d.ts +21 -28
  22. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js +27 -11
  23. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js.map +1 -1
  24. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.d.ts +70 -26
  25. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js +82 -32
  26. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js.map +1 -1
  27. package/dist/activities/execute-cursor/adapter.d.ts +8 -7
  28. package/dist/activities/execute-cursor/adapter.js +13 -9
  29. package/dist/activities/execute-cursor/adapter.js.map +1 -1
  30. package/dist/activities/execute-cursor/approval-policy.d.ts +10 -10
  31. package/dist/activities/execute-cursor/approval-policy.js +12 -23
  32. package/dist/activities/execute-cursor/approval-policy.js.map +1 -1
  33. package/dist/activities/execute-cursor/approval-state.d.ts +35 -1
  34. package/dist/activities/execute-cursor/approval-state.js +65 -0
  35. package/dist/activities/execute-cursor/approval-state.js.map +1 -1
  36. package/dist/activities/execute-cursor/{message-translator.d.ts → boundary-rows.d.ts} +45 -341
  37. package/dist/activities/execute-cursor/boundary-rows.js +1018 -0
  38. package/dist/activities/execute-cursor/boundary-rows.js.map +1 -0
  39. package/dist/activities/execute-cursor/cursor-capabilities.d.ts +1 -1
  40. package/dist/activities/execute-cursor/cursor-capabilities.js +1 -1
  41. package/dist/activities/execute-cursor/cursor-event-recorder.d.ts +33 -14
  42. package/dist/activities/execute-cursor/cursor-event-recorder.js +43 -21
  43. package/dist/activities/execute-cursor/cursor-event-recorder.js.map +1 -1
  44. package/dist/activities/execute-cursor/prompt-builder.d.ts +3 -3
  45. package/dist/activities/execute-cursor/prompt-builder.js +4 -4
  46. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  47. package/dist/activities/execute-cursor/sdk-warmup.d.ts +15 -6
  48. package/dist/activities/execute-cursor/sdk-warmup.js +15 -6
  49. package/dist/activities/execute-cursor/sdk-warmup.js.map +1 -1
  50. package/dist/activities/execute-cursor/service-tier.js +1 -2
  51. package/dist/activities/execute-cursor/service-tier.js.map +1 -1
  52. package/dist/activities/execute-cursor/session-lifecycle.d.ts +38 -59
  53. package/dist/activities/execute-cursor/session-lifecycle.js +59 -96
  54. package/dist/activities/execute-cursor/session-lifecycle.js.map +1 -1
  55. package/dist/activities/execute-cursor/session-store.d.ts +100 -0
  56. package/dist/activities/execute-cursor/session-store.js +157 -0
  57. package/dist/activities/execute-cursor/session-store.js.map +1 -0
  58. package/dist/activities/execute-cursor/sub-agent-steps.d.ts +79 -0
  59. package/dist/activities/execute-cursor/sub-agent-steps.js +180 -0
  60. package/dist/activities/execute-cursor/sub-agent-steps.js.map +1 -0
  61. package/dist/activities/execute-cursor/tool-result.d.ts +49 -0
  62. package/dist/activities/execute-cursor/tool-result.js +130 -0
  63. package/dist/activities/execute-cursor/tool-result.js.map +1 -0
  64. package/dist/activities/execute-cursor/translator.d.ts +178 -0
  65. package/dist/activities/execute-cursor/translator.js +485 -0
  66. package/dist/activities/execute-cursor/translator.js.map +1 -0
  67. package/dist/activities/execute-cursor/turn-boundary.d.ts +15 -5
  68. package/dist/activities/execute-cursor/turn-boundary.js +10 -14
  69. package/dist/activities/execute-cursor/turn-boundary.js.map +1 -1
  70. package/dist/activities/execute-cursor/turn-settle.d.ts +11 -7
  71. package/dist/activities/execute-cursor/turn-settle.js +47 -34
  72. package/dist/activities/execute-cursor/turn-settle.js.map +1 -1
  73. package/dist/activities/execute-cursor/turn-setup.d.ts +2 -2
  74. package/dist/activities/execute-cursor/turn-setup.js +5 -5
  75. package/dist/activities/execute-cursor/turn-setup.js.map +1 -1
  76. package/dist/activities/execute-cursor/turn-stream.d.ts +23 -14
  77. package/dist/activities/execute-cursor/turn-stream.js +41 -28
  78. package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
  79. package/dist/activities/execute-cursor/turn.d.ts +4 -4
  80. package/dist/activities/execute-cursor/turn.js +5 -5
  81. package/dist/activities/execute-cursor/usage-pricing.d.ts +2 -2
  82. package/dist/activities/execute-cursor/usage-pricing.js +2 -2
  83. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.d.ts +2 -2
  84. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js +2 -2
  85. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.d.ts +16 -11
  86. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js +22 -10
  87. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js.map +1 -1
  88. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js +1 -1
  89. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js.map +1 -1
  90. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.d.ts +2 -3
  91. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js +2 -3
  92. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js.map +1 -1
  93. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.d.ts +12 -3
  94. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js +18 -4
  95. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js.map +1 -1
  96. package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.d.ts +10 -1
  97. package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.js +24 -11
  98. package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.js.map +1 -1
  99. package/dist/activities/execute-deep-agent/adapter.d.ts +1 -1
  100. package/dist/activities/execute-deep-agent/adapter.js +1 -1
  101. package/dist/activities/execute-deep-agent/approval-file-change.d.ts +19 -19
  102. package/dist/activities/execute-deep-agent/approval-file-change.js +16 -15
  103. package/dist/activities/execute-deep-agent/approval-file-change.js.map +1 -1
  104. package/dist/activities/execute-deep-agent/deep-agent-capabilities.d.ts +2 -2
  105. package/dist/activities/execute-deep-agent/deep-agent-capabilities.js +2 -2
  106. package/dist/activities/execute-deep-agent/hitl.d.ts +2 -2
  107. package/dist/activities/execute-deep-agent/hitl.js +2 -2
  108. package/dist/activities/execute-deep-agent/inline-publisher.d.ts +13 -3
  109. package/dist/activities/execute-deep-agent/inline-publisher.js +3 -3
  110. package/dist/activities/execute-deep-agent/inline-publisher.js.map +1 -1
  111. package/dist/activities/execute-deep-agent/prompt-builder.d.ts +3 -3
  112. package/dist/activities/execute-deep-agent/prompt-builder.js +6 -7
  113. package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
  114. package/dist/activities/execute-deep-agent/streaming-side-effects.d.ts +16 -8
  115. package/dist/activities/execute-deep-agent/streaming-side-effects.js +20 -33
  116. package/dist/activities/execute-deep-agent/streaming-side-effects.js.map +1 -1
  117. package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +3 -3
  118. package/dist/activities/execute-deep-agent/subagent-transformer.js +1 -1
  119. package/dist/activities/execute-deep-agent/translator.d.ts +134 -0
  120. package/dist/activities/execute-deep-agent/translator.js +418 -0
  121. package/dist/activities/execute-deep-agent/translator.js.map +1 -0
  122. package/dist/activities/execute-deep-agent/turn-settle.d.ts +13 -7
  123. package/dist/activities/execute-deep-agent/turn-settle.js +34 -45
  124. package/dist/activities/execute-deep-agent/turn-settle.js.map +1 -1
  125. package/dist/activities/execute-deep-agent/turn-setup.d.ts +8 -8
  126. package/dist/activities/execute-deep-agent/turn-setup.js +7 -7
  127. package/dist/activities/execute-deep-agent/turn-stream.d.ts +13 -10
  128. package/dist/activities/execute-deep-agent/turn-stream.js +44 -41
  129. package/dist/activities/execute-deep-agent/turn-stream.js.map +1 -1
  130. package/dist/activities/execute-deep-agent/turn.d.ts +3 -3
  131. package/dist/activities/execute-deep-agent/turn.js +3 -3
  132. package/dist/config.d.ts +2 -2
  133. package/dist/harness/approval-decisions.d.ts +1 -1
  134. package/dist/harness/approval-decisions.js +1 -1
  135. package/dist/harness/capabilities.d.ts +21 -11
  136. package/dist/harness/capabilities.js +2 -2
  137. package/dist/harness/capture.d.ts +4 -4
  138. package/dist/harness/capture.js +4 -4
  139. package/dist/harness/persist-chokepoint.d.ts +3 -3
  140. package/dist/harness/persist-chokepoint.js +3 -3
  141. package/dist/harness/registry.d.ts +2 -2
  142. package/dist/harness/registry.js +2 -2
  143. package/dist/harness/run-turn.d.ts +6 -4
  144. package/dist/harness/run-turn.js +31 -9
  145. package/dist/harness/run-turn.js.map +1 -1
  146. package/dist/harness/stop-controller.d.ts +1 -1
  147. package/dist/harness/stop-controller.js +1 -1
  148. package/dist/harness/terminal-table.d.ts +7 -7
  149. package/dist/harness/terminal-table.js +7 -7
  150. package/dist/harness/transcript/builder.d.ts +182 -0
  151. package/dist/harness/transcript/builder.js +693 -0
  152. package/dist/harness/transcript/builder.js.map +1 -0
  153. package/dist/harness/transcript/events.d.ts +218 -0
  154. package/dist/harness/transcript/events.js +50 -0
  155. package/dist/harness/transcript/events.js.map +1 -0
  156. package/dist/harness/transcript/state.d.ts +110 -0
  157. package/dist/harness/transcript/state.js +148 -0
  158. package/dist/harness/transcript/state.js.map +1 -0
  159. package/dist/harness/turn-context.d.ts +54 -38
  160. package/dist/harness/turn-context.js +42 -43
  161. package/dist/harness/turn-context.js.map +1 -1
  162. package/dist/harness/types.d.ts +63 -22
  163. package/dist/harness/types.js +12 -11
  164. package/dist/harness/types.js.map +1 -1
  165. package/dist/harness/usage-accumulator.d.ts +2 -2
  166. package/dist/harness/usage-accumulator.js +2 -2
  167. package/dist/harness-adapters.d.ts +5 -4
  168. package/dist/harness-adapters.js +5 -4
  169. package/dist/harness-adapters.js.map +1 -1
  170. package/dist/middleware/approval-gate.d.ts +6 -0
  171. package/dist/middleware/approval-gate.js +7 -57
  172. package/dist/middleware/approval-gate.js.map +1 -1
  173. package/dist/middleware/cost-advisory.d.ts +3 -3
  174. package/dist/middleware/cost-advisory.js +3 -3
  175. package/dist/middleware/index.d.ts +1 -1
  176. package/dist/middleware/index.js +1 -1
  177. package/dist/runner-manager.js +1 -1
  178. package/dist/runner-manager.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-vision.d.ts +2 -1
  188. package/dist/shared/attachment-vision.js.map +1 -1
  189. package/dist/shared/attachment-zip.d.ts +2 -2
  190. package/dist/shared/attachment-zip.js +2 -2
  191. package/dist/shared/cost-guard.d.ts +2 -2
  192. package/dist/shared/cost-guard.js +2 -2
  193. package/dist/shared/exact-apply.d.ts +1 -1
  194. package/dist/shared/exact-apply.js +1 -1
  195. package/dist/shared/execution-context.d.ts +2 -2
  196. package/dist/shared/execution-context.js +2 -2
  197. package/dist/shared/extract-structured-output.d.ts +2 -2
  198. package/dist/shared/extract-structured-output.js +2 -2
  199. package/dist/shared/filereview/cas-touched.d.ts +2 -2
  200. package/dist/shared/filereview/cas-touched.js +2 -2
  201. package/dist/shared/heartbeat.d.ts +1 -1
  202. package/dist/shared/heartbeat.js +1 -1
  203. package/dist/shared/llm-backend.d.ts +0 -4
  204. package/dist/shared/llm-backend.js +0 -4
  205. package/dist/shared/llm-backend.js.map +1 -1
  206. package/dist/shared/model-error.d.ts +1 -2
  207. package/dist/shared/model-error.js +1 -2
  208. package/dist/shared/model-error.js.map +1 -1
  209. package/dist/shared/persist-decision.d.ts +18 -24
  210. package/dist/shared/persist-decision.js +19 -11
  211. package/dist/shared/persist-decision.js.map +1 -1
  212. package/dist/shared/prompt-sections.d.ts +4 -4
  213. package/dist/shared/prompt-sections.js +4 -4
  214. package/dist/shared/skill-resolver.d.ts +3 -3
  215. package/dist/shared/skill-resolver.js +3 -3
  216. package/dist/shared/status-offload.d.ts +1 -1
  217. package/dist/shared/status-offload.js +2 -2
  218. package/dist/shared/status-offload.js.map +1 -1
  219. package/dist/shared/streaming-scheduler.d.ts +2 -7
  220. package/dist/shared/streaming-scheduler.js +6 -14
  221. package/dist/shared/streaming-scheduler.js.map +1 -1
  222. package/dist/shared/subagent-rows.d.ts +2 -2
  223. package/dist/shared/subagent-rows.js +2 -2
  224. package/dist/shared/todos.d.ts +3 -3
  225. package/dist/shared/todos.js +3 -3
  226. package/dist/shared/tool-row.d.ts +19 -1
  227. package/dist/shared/tool-row.js +36 -2
  228. package/dist/shared/tool-row.js.map +1 -1
  229. package/dist/shared/worker-shutdown.d.ts +1 -1
  230. package/dist/shared/worker-shutdown.js +1 -1
  231. package/dist/shared/workspace/session-provision.d.ts +1 -1
  232. package/dist/shared/workspace/session-provision.js +1 -1
  233. package/dist/shared/workspace/sources/empty.d.ts +1 -1
  234. package/dist/shared/workspace/sources/empty.js +1 -2
  235. package/dist/shared/workspace/sources/empty.js.map +1 -1
  236. package/dist/shared/workspace/sources/git.js +4 -4
  237. package/dist/shared/workspace/sources/git.js.map +1 -1
  238. package/dist/shared/workspace/sources/local-path.js +6 -6
  239. package/dist/shared/workspace/sources/local-path.js.map +1 -1
  240. package/dist/shared/workspace/stigmer-link.d.ts +1 -1
  241. package/dist/shared/workspace/stigmer-link.js +1 -1
  242. package/dist/shared/workspace/types.d.ts +2 -5
  243. package/dist/shared/workspace/types.js +0 -6
  244. package/dist/shared/workspace/types.js.map +1 -1
  245. package/dist/shared/workspace/writeback-coordinator.d.ts +17 -4
  246. package/dist/shared/workspace/writeback-coordinator.js +7 -9
  247. package/dist/shared/workspace/writeback-coordinator.js.map +1 -1
  248. package/package.json +5 -5
  249. package/src/__test-utils__/__tests__/execution-record-barrier.test.ts +70 -0
  250. package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +35 -1
  251. package/src/__test-utils__/approval-contract/contract.ts +1 -1
  252. package/src/__test-utils__/approval-contract/types.ts +1 -1
  253. package/src/__test-utils__/harness-boot-order-child.ts +1 -1
  254. package/src/__test-utils__/harness-contract/contract.ts +8 -8
  255. package/src/__test-utils__/harness-contract/recording-sink.ts +11 -1
  256. package/src/__test-utils__/harness-contract/runtime-contract.ts +52 -16
  257. package/src/__test-utils__/harness-contract/scripted-adapter.ts +47 -43
  258. package/src/__test-utils__/hermetic-activity.ts +113 -9
  259. package/src/__test-utils__/model-registry-fixture.ts +31 -7
  260. package/src/__test-utils__/module-specifiers.ts +32 -3
  261. package/src/__tests__/harness-boot-order.test.ts +1 -1
  262. package/src/__tests__/harness-contract.test.ts +1 -1
  263. package/src/__tests__/runner-manager.test.ts +1 -1
  264. package/src/activities/execute-cursor/__test-utils__/__tests__/scripted-double.test.ts +32 -8
  265. package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +12 -10
  266. package/src/activities/execute-cursor/__test-utils__/fold.ts +116 -0
  267. package/src/activities/execute-cursor/__test-utils__/gateway-substrate.ts +1 -1
  268. package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +72 -19
  269. package/src/activities/execute-cursor/__test-utils__/scripted-agent.ts +35 -29
  270. package/src/activities/execute-cursor/__test-utils__/scripted-sdk.ts +94 -38
  271. package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +2 -1
  272. package/src/activities/execute-cursor/__tests__/approval-state.test.ts +14 -21
  273. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +3 -3
  274. package/src/activities/execute-cursor/__tests__/coarse-fingerprint.test.ts +2 -1
  275. package/src/activities/execute-cursor/__tests__/cursor-baseurl-routing.test.ts +10 -8
  276. package/src/activities/execute-cursor/__tests__/cursor-event-recorder.test.ts +142 -0
  277. package/src/activities/execute-cursor/__tests__/cursor-fetch-interceptor-bypass.test.ts +24 -12
  278. package/src/activities/execute-cursor/__tests__/cursor-generate-image-live.test.ts +7 -2
  279. package/src/activities/execute-cursor/__tests__/cursor-hook-protocol-live.test.ts +163 -0
  280. package/src/activities/execute-cursor/__tests__/cursor-sdk-auth-smoke.test.ts +23 -20
  281. package/src/activities/execute-cursor/__tests__/cursor-transcript-live.test.ts +298 -0
  282. package/src/activities/execute-cursor/__tests__/deny-gate-exact-apply.test.ts +4 -2
  283. package/src/activities/execute-cursor/__tests__/fetch-interceptor.test.ts +1 -1
  284. package/src/activities/execute-cursor/__tests__/hermetic/deny-and-retry.test.ts +5 -2
  285. package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +5 -2
  286. package/src/activities/execute-cursor/__tests__/hermetic/goldens/mcp-tool-call.status.json +71 -0
  287. package/src/activities/execute-cursor/__tests__/hermetic/goldens/sdk-task-note.status.json +73 -0
  288. package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.error-delta.status.json +78 -0
  289. package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.output-first.status.json +72 -0
  290. package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.status.json +72 -0
  291. package/src/activities/execute-cursor/__tests__/hermetic/goldens/sub-agent-delegation.status.json +109 -0
  292. package/src/activities/execute-cursor/__tests__/hermetic/goldens/thinking-turn.status.json +78 -0
  293. package/src/activities/execute-cursor/__tests__/hermetic/goldens/todo-write.status.json +119 -0
  294. package/src/activities/execute-cursor/__tests__/hermetic/goldens/tool-error.status.json +68 -0
  295. package/src/activities/execute-cursor/__tests__/hermetic/goldens/tool-only-step.status.json +67 -0
  296. package/src/activities/execute-cursor/__tests__/hermetic/goldens/unattributed-hook-block.status.json +1 -1
  297. package/src/activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts +10 -7
  298. package/src/activities/execute-cursor/__tests__/hermetic/mcp-tool-call.test.ts +146 -0
  299. package/src/activities/execute-cursor/__tests__/hermetic/pause-vs-shutdown.test.ts +8 -5
  300. package/src/activities/execute-cursor/__tests__/hermetic/plain-turn.test.ts +6 -2
  301. package/src/activities/execute-cursor/__tests__/hermetic/recovery-fresh-agent.test.ts +4 -1
  302. package/src/activities/execute-cursor/__tests__/hermetic/run-wait-arms.test.ts +6 -2
  303. package/src/activities/execute-cursor/__tests__/hermetic/sdk-task-note.test.ts +122 -0
  304. package/src/activities/execute-cursor/__tests__/hermetic/shell-output-delta.test.ts +276 -0
  305. package/src/activities/execute-cursor/__tests__/hermetic/stream-self-stop-arms.test.ts +12 -9
  306. package/src/activities/execute-cursor/__tests__/hermetic/sub-agent-delegation.test.ts +196 -0
  307. package/src/activities/execute-cursor/__tests__/hermetic/thinking-turn.test.ts +145 -0
  308. package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +4 -1
  309. package/src/activities/execute-cursor/__tests__/hermetic/todo-write.test.ts +165 -0
  310. package/src/activities/execute-cursor/__tests__/hermetic/tool-call.test.ts +7 -4
  311. package/src/activities/execute-cursor/__tests__/hermetic/tool-error.test.ts +138 -0
  312. package/src/activities/execute-cursor/__tests__/hermetic/tool-only-step.test.ts +130 -0
  313. package/src/activities/execute-cursor/__tests__/hermetic/unattributed-hook-block.test.ts +17 -2
  314. package/src/activities/execute-cursor/__tests__/hermetic/workspace-lock-timeout.test.ts +5 -2
  315. package/src/activities/execute-cursor/__tests__/hitl-ledger.test.ts +43 -60
  316. package/src/activities/execute-cursor/__tests__/hitl-resume-history.test.ts +23 -28
  317. package/src/activities/execute-cursor/__tests__/hook-script.test.ts +2 -1
  318. package/src/activities/execute-cursor/__tests__/http2-interceptor.test.ts +1 -1
  319. package/src/activities/execute-cursor/__tests__/prompt-goldens.test.ts +5 -5
  320. package/src/activities/execute-cursor/__tests__/same-identity-reproposal.test.ts +11 -13
  321. package/src/activities/execute-cursor/__tests__/sequential-gate-resume.test.ts +8 -11
  322. package/src/activities/execute-cursor/__tests__/session-lifecycle.test.ts +86 -58
  323. package/src/activities/execute-cursor/__tests__/session-store.test.ts +220 -0
  324. package/src/activities/execute-cursor/__tests__/tool-result-image.test.ts +8 -22
  325. package/src/activities/execute-cursor/__tests__/translator.test.ts +594 -0
  326. package/src/activities/execute-cursor/__tests__/turn-boundary.test.ts +8 -5
  327. package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +87 -63
  328. package/src/activities/execute-cursor/adapter.ts +13 -9
  329. package/src/activities/execute-cursor/approval-policy.ts +12 -24
  330. package/src/activities/execute-cursor/approval-state.ts +66 -1
  331. package/src/activities/execute-cursor/boundary-rows.ts +1132 -0
  332. package/src/activities/execute-cursor/cursor-capabilities.ts +1 -1
  333. package/src/activities/execute-cursor/cursor-event-recorder.ts +57 -28
  334. package/src/activities/execute-cursor/fetch-interceptor.ts +1 -1
  335. package/src/activities/execute-cursor/http2-interceptor.ts +1 -1
  336. package/src/activities/execute-cursor/prompt-builder.ts +6 -6
  337. package/src/activities/execute-cursor/sdk-warmup.ts +15 -6
  338. package/src/activities/execute-cursor/service-tier.ts +1 -2
  339. package/src/activities/execute-cursor/session-lifecycle.ts +63 -109
  340. package/src/activities/execute-cursor/session-store.ts +187 -0
  341. package/src/activities/execute-cursor/sub-agent-steps.ts +188 -0
  342. package/src/activities/execute-cursor/tool-result.ts +128 -0
  343. package/src/activities/execute-cursor/translator.ts +541 -0
  344. package/src/activities/execute-cursor/turn-boundary.ts +21 -14
  345. package/src/activities/execute-cursor/turn-settle.ts +46 -34
  346. package/src/activities/execute-cursor/turn-setup.ts +5 -5
  347. package/src/activities/execute-cursor/turn-stream.ts +49 -46
  348. package/src/activities/execute-cursor/turn.ts +5 -5
  349. package/src/activities/execute-cursor/usage-pricing.ts +2 -2
  350. package/src/activities/execute-deep-agent/__test-utils__/contract-subject.ts +2 -2
  351. package/src/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.ts +23 -11
  352. package/src/activities/execute-deep-agent/__test-utils__/hitl-script.ts +1 -1
  353. package/src/activities/execute-deep-agent/__test-utils__/scripted-model-module.ts +2 -3
  354. package/src/activities/execute-deep-agent/__test-utils__/scripted-model.ts +25 -4
  355. package/src/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.ts +25 -11
  356. package/src/activities/execute-deep-agent/__tests__/adapter-graph-is-sdk-free.test.ts +1 -1
  357. package/src/activities/execute-deep-agent/__tests__/adapter-is-temporal-free.test.ts +1 -1
  358. package/src/activities/execute-deep-agent/__tests__/approval-file-change.test.ts +6 -17
  359. package/src/activities/execute-deep-agent/__tests__/hermetic/file-review-capture.test.ts +25 -8
  360. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn1.status.json +2 -7
  361. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn2.status.json +4 -14
  362. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve.turn2.status.json +1 -5
  363. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/file-review-capture.status.json +4 -7
  364. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/gate.turn1.status.json +1 -5
  365. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn1.status.json +2 -9
  366. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn2.status.json +2 -9
  367. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.after-tool.status.json +1 -4
  368. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.mid-tool.status.json +1 -4
  369. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/platform-stop.status.json +1 -4
  370. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/recursion-limit.persisted.status.json +109 -76
  371. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/reject.turn2.status.json +1 -5
  372. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn2.status.json +2 -10
  373. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn3.status.json +2 -10
  374. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/skip.turn2.status.json +1 -5
  375. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sub-agent-delegation.status.json +3 -6
  376. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/tool-call.status.json +1 -4
  377. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/worker-shutdown.status.json +1 -4
  378. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/write-todos.status.json +92 -0
  379. package/src/activities/execute-deep-agent/__tests__/hermetic/harness-contract.test.ts +3 -3
  380. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-approve-all-lease.test.ts +9 -5
  381. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-round-trips.test.ts +3 -3
  382. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-sequential-gates.test.ts +3 -3
  383. package/src/activities/execute-deep-agent/__tests__/hermetic/inline-artifact-across-gate.test.ts +7 -6
  384. package/src/activities/execute-deep-agent/__tests__/hermetic/pause-vs-shutdown.test.ts +10 -11
  385. package/src/activities/execute-deep-agent/__tests__/hermetic/plain-turn.test.ts +4 -4
  386. package/src/activities/execute-deep-agent/__tests__/hermetic/platform-stop.test.ts +9 -8
  387. package/src/activities/execute-deep-agent/__tests__/hermetic/recursion-limit.test.ts +21 -13
  388. package/src/activities/execute-deep-agent/__tests__/hermetic/resolution-error.test.ts +2 -2
  389. package/src/activities/execute-deep-agent/__tests__/hermetic/structured-output.test.ts +7 -7
  390. package/src/activities/execute-deep-agent/__tests__/hermetic/sub-agent-delegation.test.ts +28 -12
  391. package/src/activities/execute-deep-agent/__tests__/hermetic/tool-call.test.ts +21 -21
  392. package/src/activities/execute-deep-agent/__tests__/hermetic/workspace-lock-timeout.test.ts +5 -5
  393. package/src/activities/execute-deep-agent/__tests__/hermetic/write-todos.test.ts +160 -0
  394. package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +35 -30
  395. package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +3 -4
  396. package/src/activities/execute-deep-agent/__tests__/prompt-goldens.test.ts +12 -10
  397. package/src/activities/execute-deep-agent/__tests__/scripted-model.test.ts +13 -3
  398. package/src/activities/execute-deep-agent/__tests__/streaming-side-effects.test.ts +26 -18
  399. package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +1 -1
  400. package/src/activities/execute-deep-agent/__tests__/{subagent-tracker.test.ts → translator-subagents.test.ts} +76 -57
  401. package/src/activities/execute-deep-agent/__tests__/{v3-status-builder.test.ts → translator-through-builder.test.ts} +213 -299
  402. package/src/activities/execute-deep-agent/__tests__/translator.test.ts +505 -0
  403. package/src/activities/execute-deep-agent/__tests__/turn-stream.test.ts +11 -29
  404. package/src/activities/execute-deep-agent/adapter.ts +1 -1
  405. package/src/activities/execute-deep-agent/approval-file-change.ts +20 -22
  406. package/src/activities/execute-deep-agent/deep-agent-capabilities.ts +2 -2
  407. package/src/activities/execute-deep-agent/hitl.ts +2 -2
  408. package/src/activities/execute-deep-agent/inline-publisher.ts +16 -5
  409. package/src/activities/execute-deep-agent/prompt-builder.ts +6 -7
  410. package/src/activities/execute-deep-agent/streaming-side-effects.ts +22 -31
  411. package/src/activities/execute-deep-agent/subagent-transformer.ts +3 -3
  412. package/src/activities/execute-deep-agent/translator.ts +463 -0
  413. package/src/activities/execute-deep-agent/turn-settle.ts +35 -43
  414. package/src/activities/execute-deep-agent/turn-setup.ts +8 -8
  415. package/src/activities/execute-deep-agent/turn-stream.ts +53 -51
  416. package/src/activities/execute-deep-agent/turn.ts +3 -3
  417. package/src/config.ts +2 -2
  418. package/src/harness/README.md +335 -0
  419. package/src/harness/__tests__/approval-decisions.test.ts +2 -2
  420. package/src/harness/__tests__/capture.test.ts +3 -3
  421. package/src/harness/__tests__/import-direction.test.ts +3 -2
  422. package/src/harness/__tests__/mount-skills.test.ts +4 -1
  423. package/src/harness/__tests__/readme-index.test.ts +339 -0
  424. package/src/harness/__tests__/run-turn.test.ts +131 -6
  425. package/src/harness/__tests__/transcript-is-engine-free.test.ts +83 -0
  426. package/src/harness/__tests__/transcript-writers.test.ts +191 -0
  427. package/src/harness/__tests__/turn-attachments-vision.test.ts +5 -2
  428. package/src/harness/__tests__/turn-context.test.ts +5 -5
  429. package/src/harness/approval-decisions.ts +1 -1
  430. package/src/harness/capabilities.ts +21 -11
  431. package/src/harness/capture.ts +4 -4
  432. package/src/harness/persist-chokepoint.ts +3 -3
  433. package/src/harness/registry.ts +2 -2
  434. package/src/harness/run-turn.ts +33 -9
  435. package/src/harness/stop-controller.ts +1 -1
  436. package/src/harness/terminal-table.ts +7 -7
  437. package/src/harness/transcript/__tests__/builder.test.ts +975 -0
  438. package/src/harness/transcript/__tests__/state.test.ts +143 -0
  439. package/src/harness/transcript/builder.ts +755 -0
  440. package/src/harness/transcript/events.ts +262 -0
  441. package/src/harness/transcript/state.ts +167 -0
  442. package/src/harness/turn-context.ts +61 -46
  443. package/src/harness/types.ts +64 -22
  444. package/src/harness/usage-accumulator.ts +2 -2
  445. package/src/harness-adapters.ts +5 -4
  446. package/src/middleware/__tests__/cost-advisory.test.ts +2 -2
  447. package/src/middleware/approval-gate.ts +7 -74
  448. package/src/middleware/cost-advisory.ts +3 -3
  449. package/src/middleware/index.ts +1 -1
  450. package/src/runner-manager.ts +1 -1
  451. package/src/shared/__tests__/approval-policy.test.ts +45 -0
  452. package/src/shared/__tests__/args-preview.test.ts +40 -20
  453. package/src/shared/__tests__/attachment-naming.test.ts +1 -1
  454. package/src/shared/__tests__/attachment-resolver.test.ts +5 -5
  455. package/src/shared/__tests__/attachment-zip.test.ts +1 -1
  456. package/src/shared/__tests__/blueprint-resolver.test.ts +1 -1
  457. package/src/shared/__tests__/cost-guard.test.ts +1 -1
  458. package/src/shared/__tests__/exact-apply.test.ts +2 -1
  459. package/src/shared/__tests__/persist-decision.test.ts +19 -33
  460. package/src/shared/__tests__/prompt-sections.test.ts +1 -1
  461. package/src/shared/__tests__/stamp-flowed-rows.test.ts +1 -1
  462. package/src/shared/__tests__/status-offload.test.ts +1 -1
  463. package/src/shared/__tests__/streaming-scheduler.test.ts +8 -9
  464. package/src/shared/__tests__/todos.test.ts +1 -1
  465. package/src/shared/__tests__/tool-row.test.ts +1 -1
  466. package/src/shared/approval-policy.ts +95 -0
  467. package/src/shared/args-preview.ts +51 -42
  468. package/src/shared/attachment-resolver.ts +4 -4
  469. package/src/shared/attachment-vision.ts +2 -1
  470. package/src/shared/attachment-zip.ts +2 -2
  471. package/src/shared/cost-guard.ts +2 -2
  472. package/src/shared/exact-apply.ts +1 -1
  473. package/src/shared/execution-context.ts +2 -2
  474. package/src/shared/extract-structured-output.ts +2 -2
  475. package/src/shared/filereview/__tests__/capture.test.ts +9 -5
  476. package/src/shared/filereview/__tests__/git-substrate.test.ts +4 -1
  477. package/src/shared/filereview/__tests__/proxy-reconcile.test.ts +3 -3
  478. package/src/shared/filereview/cas-touched.ts +2 -2
  479. package/src/shared/heartbeat.ts +1 -1
  480. package/src/shared/llm-backend.ts +0 -4
  481. package/src/shared/model-error.ts +1 -2
  482. package/src/shared/persist-decision.ts +19 -28
  483. package/src/shared/prompt-sections.ts +4 -4
  484. package/src/shared/skill-resolver.ts +3 -3
  485. package/src/shared/status-offload.ts +2 -2
  486. package/src/shared/streaming-scheduler.ts +8 -13
  487. package/src/shared/subagent-rows.ts +2 -2
  488. package/src/shared/todos.ts +3 -3
  489. package/src/shared/tool-row.ts +38 -2
  490. package/src/shared/worker-shutdown.ts +1 -1
  491. package/src/shared/workspace/__tests__/git-source.test.ts +3 -3
  492. package/src/shared/workspace/__tests__/provisioner.test.ts +5 -5
  493. package/src/shared/workspace/__tests__/session-provision.test.ts +2 -2
  494. package/src/shared/workspace/__tests__/writeback-coordinator.integration.test.ts +8 -9
  495. package/src/shared/workspace/__tests__/writeback-coordinator.test.ts +25 -25
  496. package/src/shared/workspace/provisioner.ts +1 -1
  497. package/src/shared/workspace/session-provision.ts +1 -1
  498. package/src/shared/workspace/sources/empty.ts +2 -2
  499. package/src/shared/workspace/sources/git.ts +3 -4
  500. package/src/shared/workspace/sources/local-path.ts +5 -6
  501. package/src/shared/workspace/stigmer-link.ts +1 -1
  502. package/src/shared/workspace/types.ts +2 -5
  503. package/src/shared/workspace/writeback-coordinator.ts +23 -12
  504. package/dist/activities/execute-cursor/delta-enricher.d.ts +0 -87
  505. package/dist/activities/execute-cursor/delta-enricher.js +0 -265
  506. package/dist/activities/execute-cursor/delta-enricher.js.map +0 -1
  507. package/dist/activities/execute-cursor/message-translator.js +0 -2040
  508. package/dist/activities/execute-cursor/message-translator.js.map +0 -1
  509. package/dist/activities/execute-cursor/todo-tracker.d.ts +0 -40
  510. package/dist/activities/execute-cursor/todo-tracker.js +0 -80
  511. package/dist/activities/execute-cursor/todo-tracker.js.map +0 -1
  512. package/dist/activities/execute-deep-agent/execution-state.d.ts +0 -54
  513. package/dist/activities/execute-deep-agent/execution-state.js +0 -68
  514. package/dist/activities/execute-deep-agent/execution-state.js.map +0 -1
  515. package/dist/activities/execute-deep-agent/status-builder-shared.d.ts +0 -65
  516. package/dist/activities/execute-deep-agent/status-builder-shared.js +0 -90
  517. package/dist/activities/execute-deep-agent/status-builder-shared.js.map +0 -1
  518. package/dist/activities/execute-deep-agent/subagent-tracker.d.ts +0 -113
  519. package/dist/activities/execute-deep-agent/subagent-tracker.js +0 -400
  520. package/dist/activities/execute-deep-agent/subagent-tracker.js.map +0 -1
  521. package/dist/activities/execute-deep-agent/v3-events.d.ts +0 -102
  522. package/dist/activities/execute-deep-agent/v3-events.js +0 -35
  523. package/dist/activities/execute-deep-agent/v3-events.js.map +0 -1
  524. package/dist/activities/execute-deep-agent/v3-protocol-normalizer.d.ts +0 -15
  525. package/dist/activities/execute-deep-agent/v3-protocol-normalizer.js +0 -235
  526. package/dist/activities/execute-deep-agent/v3-protocol-normalizer.js.map +0 -1
  527. package/dist/activities/execute-deep-agent/v3-status-builder.d.ts +0 -111
  528. package/dist/activities/execute-deep-agent/v3-status-builder.js +0 -457
  529. package/dist/activities/execute-deep-agent/v3-status-builder.js.map +0 -1
  530. package/dist/shared/execution-status-writer.d.ts +0 -31
  531. package/dist/shared/execution-status-writer.js +0 -43
  532. package/dist/shared/execution-status-writer.js.map +0 -1
  533. package/src/activities/execute-cursor/__tests__/delta-enricher.test.ts +0 -310
  534. package/src/activities/execute-cursor/__tests__/message-translator.test.ts +0 -1033
  535. package/src/activities/execute-cursor/__tests__/todo-tracker.test.ts +0 -498
  536. package/src/activities/execute-cursor/delta-enricher.ts +0 -307
  537. package/src/activities/execute-cursor/message-translator.ts +0 -2319
  538. package/src/activities/execute-cursor/todo-tracker.ts +0 -91
  539. package/src/activities/execute-deep-agent/__tests__/execution-state-extended.test.ts +0 -148
  540. package/src/activities/execute-deep-agent/__tests__/execution-state.test.ts +0 -154
  541. package/src/activities/execute-deep-agent/__tests__/status-builder-shared.test.ts +0 -47
  542. package/src/activities/execute-deep-agent/__tests__/v3-protocol-normalizer.test.ts +0 -324
  543. package/src/activities/execute-deep-agent/execution-state.ts +0 -78
  544. package/src/activities/execute-deep-agent/status-builder-shared.ts +0 -142
  545. package/src/activities/execute-deep-agent/subagent-tracker.ts +0 -479
  546. package/src/activities/execute-deep-agent/v3-events.ts +0 -153
  547. package/src/activities/execute-deep-agent/v3-protocol-normalizer.ts +0 -264
  548. package/src/activities/execute-deep-agent/v3-status-builder.ts +0 -565
  549. package/src/shared/execution-status-writer.ts +0 -56
@@ -11,12 +11,15 @@
11
11
  * registry the harness reads at setup, the Cursor `Config` slice, and the
12
12
  * per-scenario reset of the harness's module-level caches.
13
13
  *
14
- * What the two `vi.mock` calls a scenario file must carry look like — they are
15
- * hoisted by vitest and so cannot live here:
14
+ * What the three `vi.mock` calls a scenario file must carry look like — they
15
+ * are hoisted by vitest and so cannot live here (the SDK's sqlite entry is a
16
+ * separate module id, so it is doubled separately; `scripted-sdk.ts`):
16
17
  *
17
18
  * ```ts
18
19
  * vi.mock("@cursor/sdk", async () =>
19
20
  * (await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSdkModule());
21
+ * vi.mock("@cursor/sdk/sqlite", async () =>
22
+ * (await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSqliteModule());
20
23
  * vi.mock("../../../../client/stigmer-client.js", async () =>
21
24
  * (await import("../../../../__test-utils__/hermetic-activity.js")).hermeticStigmerClientModule());
22
25
  * ```
@@ -39,6 +42,18 @@
39
42
  * the SDK double (`ScriptedSdkOptions`); an SDK-side cancel or a mid-stream
40
43
  * wedge as an `effect` step on the run. Nothing here is a switch in production
41
44
  * code — every knob is a value the production path already reads.
45
+ *
46
+ * Two postures, two entries, one turn runner. `beginCursorScenario` is the
47
+ * hermetic posture: the SDK doubled by the scenario file's `vi.mock`, the
48
+ * clock scripted, goldens byte-stable. `beginLiveCursorScenario` is the live
49
+ * posture (#1097's live-run gate): the scenario file mocks ONLY the
50
+ * client, the real `@cursor/sdk` runs under the real activity on the real
51
+ * clock with a real member key, and what the activity persists is read back
52
+ * from the same record. A live scenario therefore has no `sdk` and no `clock`
53
+ * — the type says which posture a file is in — and `runCursorTurn` reads only
54
+ * what both have. The registry fixture's `live` pass-through and the
55
+ * environment's `eventRecordingDir` are the live posture's two other
56
+ * seams, each on the module that owns the concern.
42
57
  */
43
58
 
44
59
  import { execFileSync } from "node:child_process";
@@ -213,20 +228,27 @@ export function resetCursorModuleState(): void {
213
228
  _resetRegistryCache();
214
229
  }
215
230
 
216
- export interface CursorScenario {
231
+ /** What both postures share: the environment, the record the activity persists into, the runner's `Config`. */
232
+ export interface CursorScenarioBase {
217
233
  readonly env: HermeticEnvironment;
218
- readonly clock: ScriptedClock;
219
234
  readonly record: ExecutionRecord;
220
- readonly sdk: ScriptedCursorSdk;
221
235
  /** The runner this scenario runs on: the OSS posture plus the scenario's knobs. */
222
236
  readonly config: Config;
223
237
  }
224
238
 
225
- export interface CursorScenarioOptions {
226
- readonly env: HermeticEnvironment;
239
+ /** The hermetic posture: the SDK double and the scripted clock beside the shared three. */
240
+ export interface CursorScenario extends CursorScenarioBase {
227
241
  readonly clock: ScriptedClock;
242
+ readonly sdk: ScriptedCursorSdk;
243
+ }
244
+
245
+ /** The live posture (header): the shared three and nothing doubled but the client. */
246
+ export type LiveCursorScenario = CursorScenarioBase;
247
+
248
+ /** The options both postures take. */
249
+ interface CursorScenarioBaseOptions {
250
+ readonly env: HermeticEnvironment;
228
251
  readonly record: ExecutionRecord;
229
- readonly sdk: ScriptedSdkOptions;
230
252
  /**
231
253
  * Control-plane facets the scenario opts INTO, or faults it injects, over
232
254
  * the record's everyday answers (`ExecutionRecord.client`): a rejecting
@@ -242,21 +264,50 @@ export interface CursorScenarioOptions {
242
264
  readonly config?: Partial<Config>;
243
265
  }
244
266
 
245
- /** Bind the record and the SDK for a scenario; resets the harness caches first. */
246
- export function beginCursorScenario(options: CursorScenarioOptions): CursorScenario {
267
+ export interface CursorScenarioOptions extends CursorScenarioBaseOptions {
268
+ readonly clock: ScriptedClock;
269
+ readonly sdk: ScriptedSdkOptions;
270
+ }
271
+
272
+ export interface LiveCursorScenarioOptions extends CursorScenarioBaseOptions {
273
+ /** The real member key the real SDK authenticates with; becomes `config.cursorApiKey`. */
274
+ readonly apiKey: string;
275
+ }
276
+
277
+ /**
278
+ * What every scenario begins with: the harness caches dropped, the record
279
+ * bound as the control plane the activity will talk to, the OSS `Config`
280
+ * over the environment with the scenario's knobs laid on top.
281
+ */
282
+ function beginScenarioBase(options: CursorScenarioBaseOptions): CursorScenarioBase {
247
283
  resetCursorModuleState();
248
- const sdk = new ScriptedCursorSdk(options.sdk);
249
- bindScriptedSdk(sdk);
250
284
  bindHermeticClient(options.record.client(options.clientOverrides));
251
285
  return {
252
286
  env: options.env,
253
- clock: options.clock,
254
287
  record: options.record,
255
- sdk,
256
288
  config: { ...hermeticCursorConfig(options.env), ...options.config },
257
289
  };
258
290
  }
259
291
 
292
+ /** Bind the record and the SDK double for a hermetic scenario; resets the harness caches first. */
293
+ export function beginCursorScenario(options: CursorScenarioOptions): CursorScenario {
294
+ const base = beginScenarioBase(options);
295
+ const sdk = new ScriptedCursorSdk(options.sdk);
296
+ bindScriptedSdk(sdk);
297
+ return { ...base, clock: options.clock, sdk };
298
+ }
299
+
300
+ /**
301
+ * Bind the record for a live scenario; resets the harness caches first. No
302
+ * SDK double is built or bound — the scenario file must NOT mock `@cursor/sdk`
303
+ * — and no clock is installed. The key lands on the `Config` exactly where
304
+ * the OSS runner's direct mode reads it (`turn-setup.ts`, `config.cursorApiKey`).
305
+ */
306
+ export function beginLiveCursorScenario(options: LiveCursorScenarioOptions): LiveCursorScenario {
307
+ const base = beginScenarioBase(options);
308
+ return { ...base, config: { ...base.config, cursorApiKey: options.apiKey } };
309
+ }
310
+
260
311
  export interface CursorTurnOptions {
261
312
  /** Empty for a first invocation; the agent id for a HITL reinvocation. */
262
313
  readonly threadId?: string;
@@ -266,13 +317,15 @@ export interface CursorTurnOptions {
266
317
  }
267
318
 
268
319
  /**
269
- * Run ONE `ExecuteCursor` invocation for the scenario: the real Cursor
270
- * adapter under the real turn runtime, as the composition roots wire them.
271
- * Built per invocation (the registry constructs its client, which is the one
272
- * bound at `beginCursorScenario`; the adapter boots on the scenario's config).
320
+ * Run ONE `ExecuteCursor` invocation for the scenario — either posture: the
321
+ * real Cursor adapter under the real turn runtime, as the composition roots
322
+ * wire them. Built per invocation (the registry constructs its client, which
323
+ * is the one bound at `begin*CursorScenario`; the adapter boots on the
324
+ * scenario's config). Reads only the record and the config, which both
325
+ * postures have.
273
326
  */
274
327
  export async function runCursorTurn(
275
- scenario: CursorScenario,
328
+ scenario: CursorScenarioBase,
276
329
  options: CursorTurnOptions = {},
277
330
  ): Promise<ActivityInvocation> {
278
331
  // Imported lazily so the scenario file's `vi.mock` declarations are in
@@ -15,7 +15,12 @@
15
15
  * So a turn is a SCRIPT of ordered steps, one of four kinds:
16
16
  *
17
17
  * - `event(SDKMessage)` — yielded from `stream()`
18
- * - `delta(update)` — fired through `onDelta` (usage, `turn-ended`)
18
+ * - `delta(update)` — fired through `onDelta`: any `InteractionUpdate`
19
+ * (the `turn-ended` usage the loop prices; the
20
+ * tool-call timings, shell output and completion
21
+ * status the transcript folds — #1097 widened
22
+ * the step from `turn-ended` alone so the delta
23
+ * channel has an end-to-end net)
19
24
  * - `effect(fn)` — the side effect the SDK would have performed
20
25
  * (run the real hook, write a workspace file,
21
26
  * cancel the activity from the outside)
@@ -24,16 +29,12 @@
24
29
  * The same shape as the native harness's `__test-utils__/scripted-model.ts`
25
30
  * (`ScriptStep`, driven in order), applied to the SDK's event surface.
26
31
  *
27
- * Typing: `SDKMessage`, `Run`, `RunResult` and `SDKAgent` are the SDK's own
28
- * types (`@cursor/sdk` 1.0.13, concrete in `messages.d.ts` / `run.d.ts` /
29
- * `agent.d.ts`), so a script that drifts from the real event shape fails
30
- * `tsc`. The delta channel is the exception: `InteractionUpdate` re-exports
31
- * from `@anysphere/cursor-sdk-shared`, a workspace package the published SDK
32
- * does not ship, so under `skipLibCheck` it resolves to `any` — in production
33
- * code too (`turn-stream.ts`, `delta-enricher.ts` read it untyped). The one
34
- * delta this double emits, the `turn-ended` usage, is therefore typed HERE
35
- * ({@link TurnEndedUsageDelta}) against what `turn-stream.ts` reads from it,
36
- * and that gap is recorded in the entry's findings rather than papered over.
32
+ * Typing: `SDKMessage`, `Run`, `RunResult`, `SDKAgent` and the delta channel's
33
+ * `InteractionUpdate` are the SDK's own types (`@cursor/sdk` 1.0.31, concrete
34
+ * in `messages.d.ts` / `run.d.ts` / `agent.d.ts` / the vendored `delta-types`),
35
+ * so a script that drifts from the real event shape fails `tsc`. (At 1.0.13
36
+ * the delta types resolved to `any` and the one delta this double emitted was
37
+ * typed locally; stigmer/stigmer#1053 closed that gap.)
37
38
  *
38
39
  * Cancellation: `run.cancel()` is how the harness stops a turn (first denial,
39
40
  * cost cap, stall). The double honours it the way the SDK does — the stream
@@ -50,6 +51,9 @@
50
51
  */
51
52
 
52
53
  import type {
54
+ AgentUsage,
55
+ GetUsageOptions,
56
+ InteractionUpdate,
53
57
  ModelSelection,
54
58
  Run,
55
59
  RunOperation,
@@ -59,6 +63,7 @@ import type {
59
63
  SDKMessage,
60
64
  SDKUserMessage,
61
65
  SendOptions,
66
+ TurnEndedUpdate,
62
67
  } from "@cursor/sdk";
63
68
  import type { ConversationTurn } from "@cursor/sdk";
64
69
 
@@ -66,21 +71,6 @@ import type { ConversationTurn } from "@cursor/sdk";
66
71
  // Script steps
67
72
  // ---------------------------------------------------------------------------
68
73
 
69
- /**
70
- * The `turn-ended` delta as `turn-stream.ts` reads it (`update.type ===
71
- * "turn-ended" && update.usage` -> `usageAccumulator.addTurn(update.usage)`).
72
- * See the module header for why this is typed locally.
73
- */
74
- export interface TurnEndedUsageDelta {
75
- readonly type: "turn-ended";
76
- readonly usage: {
77
- readonly inputTokens?: number;
78
- readonly outputTokens?: number;
79
- readonly cacheWriteTokens?: number;
80
- readonly cacheReadTokens?: number;
81
- };
82
- }
83
-
84
74
  /** What an `effect` step can reach: the run it is part of. */
85
75
  export interface EffectContext {
86
76
  readonly run: ScriptedRun;
@@ -89,7 +79,7 @@ export interface EffectContext {
89
79
 
90
80
  export type ScriptStep =
91
81
  | { readonly kind: "event"; readonly event: SDKMessage }
92
- | { readonly kind: "delta"; readonly update: TurnEndedUsageDelta }
82
+ | { readonly kind: "delta"; readonly update: InteractionUpdate }
93
83
  | { readonly kind: "effect"; readonly label: string; readonly run: (ctx: EffectContext) => void | Promise<void> }
94
84
  | { readonly kind: "result"; readonly result: Omit<RunResult, "id"> };
95
85
 
@@ -101,7 +91,12 @@ export const step = {
101
91
  event(event: SDKMessage): ScriptStep {
102
92
  return { kind: "event", event };
103
93
  },
104
- turnEnded(usage: TurnEndedUsageDelta["usage"]): ScriptStep {
94
+ /** Any delta the SDK fires through `onDelta` between stream events: tool-call timings, shell output, a completion's status. */
95
+ delta(update: InteractionUpdate): ScriptStep {
96
+ return { kind: "delta", update };
97
+ },
98
+ /** The `turn-ended` delta `turn-stream.ts` prices; the SDK's shape, all four counts stated. */
99
+ turnEnded(usage: NonNullable<TurnEndedUpdate["usage"]>): ScriptStep {
105
100
  return { kind: "delta", update: { type: "turn-ended", usage } };
106
101
  },
107
102
  effect(label: string, run: (ctx: EffectContext) => void | Promise<void>): ScriptStep {
@@ -145,6 +140,10 @@ export function sdkEvents(agentId: string, runId: string) {
145
140
  status(status: "CREATING" | "RUNNING" | "FINISHED" | "ERROR" | "CANCELLED" | "EXPIRED", message?: string): SDKMessage {
146
141
  return { type: "status", ...base, status, message };
147
142
  },
143
+ /** The SDK's `task` event: a status line about the run in the agent's own voice, which the transcript shows as a SYSTEM message. */
144
+ task(text: string, status?: string): SDKMessage {
145
+ return { type: "task", ...base, text, status };
146
+ },
148
147
  };
149
148
  }
150
149
 
@@ -224,7 +223,7 @@ export class ScriptedRun implements Run {
224
223
  yield s.event;
225
224
  break;
226
225
  case "delta":
227
- await this.onDelta?.({ update: s.update as never });
226
+ await this.onDelta?.({ update: s.update });
228
227
  break;
229
228
  case "effect":
230
229
  await s.run({ run: this, agent: this.agent });
@@ -365,4 +364,11 @@ export class ScriptedCursorAgent implements SDKAgent {
365
364
  async downloadArtifact(_path: string): Promise<Buffer> {
366
365
  throw new Error("ScriptedCursorAgent: artifacts are not part of the scripted surface");
367
366
  }
367
+
368
+ async getUsage(_options?: GetUsageOptions): Promise<AgentUsage> {
369
+ // The harness prices the `turn-ended` delta itself (`usage-pricing.ts`) and
370
+ // never asks the SDK for billed usage; a call here is a test bug, like a
371
+ // `send()` with no script.
372
+ throw new Error("ScriptedCursorAgent: getUsage() is not part of the scripted surface");
373
+ }
368
374
  }
@@ -1,11 +1,16 @@
1
1
  /**
2
2
  * The `@cursor/sdk` module a hermetic `ExecuteCursor` run imports — every
3
- * runtime surface the activity path touches, backed by scripted agents.
3
+ * runtime surface the activity path touches, backed by scripted agents — and
4
+ * the `@cursor/sdk/sqlite` module beside it, backed by a store that holds
5
+ * nothing.
4
6
  *
5
- * The activity reaches the SDK at three runtime sites and nowhere else:
7
+ * The activity reaches the SDK at four runtime sites and nowhere else:
6
8
  *
7
- * - `session-lifecycle.ts`: `Agent.create(options)`, `Agent.resume(id, options)`,
8
- * `Agent.archive(id, ...)` — the agent handle.
9
+ * - `session-lifecycle.ts`: `Agent.create(options)`, `Agent.resume(id, options)`
10
+ * — the agent handle.
11
+ * - `session-store.ts`: `SqliteLocalAgentStore.open({ workspaceRef, stateRoot })`
12
+ * from `@cursor/sdk/sqlite` — the session's store the handle is created and
13
+ * resumed over (`local.store`).
9
14
  * - `service-tier.ts`: `Cursor.models.list({ apiKey })` — the catalog the
10
15
  * variant params (`fast`, `thinking`) are pinned from.
11
16
  * - `index.ts` outer catch: `import("@cursor/sdk")` for `CursorSdkError`, the
@@ -13,35 +18,42 @@
13
18
  *
14
19
  * Neither the SDK nor the client is injectable into the activity (the real
15
20
  * seam arrives with the harness contract; parent Q1/Q2), so — exactly as the
16
- * native activity tests already do for their boundary modules — the module is
17
- * substituted with `vi.mock`. Three existing tests each mock ONE of these
21
+ * native activity tests already do for their boundary modules — the modules
22
+ * are substituted with `vi.mock`. Three existing tests each mock ONE of these
18
23
  * surfaces (`session-lifecycle.test.ts`, `service-tier.test.ts`,
19
- * `sdk-warmup.test.ts`); a whole-activity run needs all three at once, which is
20
- * what this module is.
24
+ * `sdk-warmup.test.ts`); a whole-activity run needs all of them at once, which
25
+ * is what this module is.
21
26
  *
22
- * `vi.mock` is hoisted and must appear in the test file; the factory can
23
- * `await import()` this module and return {@link scriptedCursorSdkModule}. The
24
- * module's statics read the {@link ScriptedCursorSdk} bound for the current
27
+ * `vi.mock` is hoisted and must appear in the test file, once per module id
28
+ * (a subpath is its own module id, so `@cursor/sdk/sqlite` needs its own
29
+ * `vi.mock`); the factories `await import()` this module and return
30
+ * {@link scriptedCursorSdkModule} and {@link scriptedCursorSqliteModule}. The
31
+ * modules' statics read the {@link ScriptedCursorSdk} bound for the current
25
32
  * scenario ({@link bindScriptedSdk}), so one test file can run several
26
- * scenarios with different agents against the same mocked module.
33
+ * scenarios with different agents against the same mocked modules.
27
34
  *
28
35
  * Resolution rules a scenario declares, mirroring what the real SDK does:
29
36
  * - `Agent.create` hands out the agent declared for the session it is asked
30
- * for (`agentForSession`, when the scenario resolves agents per session —
31
- * the harness contract kit runs several sessions concurrently on one
32
- * adapter, and the order their creates arrive in is real I/O timing), else
33
- * the NEXT unclaimed agent in `agents` (turn 1 of a fresh session; the fresh
34
- * agent of a poisoned-handle recovery) — unless the scenario declared a
35
- * `createFailure`, which the FIRST create throws instead (the SDK refusing
37
+ * for (`agentForWorkspaceRef`, when the scenario resolves agents per
38
+ * session — the harness contract kit runs several sessions concurrently on
39
+ * one adapter, and the order their creates arrive in is real I/O timing),
40
+ * else the NEXT unclaimed agent in `agents` (turn 1 of a fresh session; the
41
+ * fresh agent of a poisoned-handle recovery) — unless the scenario declared
42
+ * a `createFailure`, which the FIRST create throws instead (the SDK refusing
36
43
  * to mint an agent: a 401 on the key, a validation error).
37
44
  * - `Agent.resume(id)` hands back the agent with that id if the scenario
38
45
  * declared it (in `agents` or `resumableAgents`, or handed out for a
39
46
  * session), else throws — `resolveAgent` then falls back to `create`, which
40
47
  * is the production shape of a lost handle.
41
48
  * - `Cursor.models.list` answers the scenario's catalog.
49
+ * - `SqliteLocalAgentStore.open` hands out a {@link ScriptedLocalAgentStore}
50
+ * carrying the ref and root it was asked for, and records the open; its
51
+ * `dispose()` is recorded too, so a scenario can assert the adapter's
52
+ * session-store lifetime (`releaseSession`, `shutdown`).
42
53
  */
43
54
 
44
55
  import type { AgentOptions, ModelListItem, SDKAgent } from "@cursor/sdk";
56
+ import type { SqliteLocalAgentStore, SqliteLocalAgentStoreOptions } from "@cursor/sdk/sqlite";
45
57
  import type { ScriptedCursorAgent } from "./scripted-agent.js";
46
58
 
47
59
  export interface ScriptedSdkOptions {
@@ -50,12 +62,12 @@ export interface ScriptedSdkOptions {
50
62
  /**
51
63
  * The agent `Agent.create` hands out for the session the create names,
52
64
  * consulted before the ordered list. The SDK's create options carry the
53
- * session as `platform.workspaceRef` (`session-lifecycle.ts`
54
- * `resolvePlatformOptions`: `stigmer-session:<sessionId>`), so the resolver
55
- * is keyed by that ref — a scenario computes the ref the same way the
56
- * adapter does. `undefined` falls through to the list. Consulted live on
57
- * every create, so a scenario may mint the session's agent only when it
58
- * learns of the session.
65
+ * session as the store's `workspaceRef` (`local.store`, opened by
66
+ * `session-store.ts`: `stigmer-session:<sessionId>`), so the resolver is
67
+ * keyed by that ref — a scenario computes the ref the same way the adapter
68
+ * does (`resolveSessionStoreLocation`). `undefined` falls through to the
69
+ * list. Consulted live on every create, so a scenario may mint the session's
70
+ * agent only when it learns of the session.
59
71
  */
60
72
  readonly agentForWorkspaceRef?: (workspaceRef: string) => ScriptedCursorAgent | undefined;
61
73
  /**
@@ -82,21 +94,46 @@ export interface RecordedResolution {
82
94
  }
83
95
 
84
96
  /**
85
- * The `platform.workspaceRef` a create names, read defensively: the platform
86
- * option's type re-exports from the unshipped `@anysphere/cursor-sdk-local-runtime`
87
- * and resolves to `any` under `skipLibCheck` (the same gap `scripted-agent.ts`
88
- * records for the delta channel), so the shape is checked here, not assumed.
97
+ * The session a create names: the `workspaceRef` of the store it passes as
98
+ * `local.store`. In a hermetic run that store is the one this module's sqlite
99
+ * double opened; anything else (a test that mocks `@cursor/sdk` with its own
100
+ * stub and passes no store) names no session and falls through to the list.
89
101
  */
90
102
  function workspaceRefOf(options: AgentOptions): string | undefined {
91
- const platform: unknown = (options as { platform?: unknown }).platform;
92
- if (typeof platform !== "object" || platform === null) return undefined;
93
- const ref = (platform as { workspaceRef?: unknown }).workspaceRef;
94
- return typeof ref === "string" ? ref : undefined;
103
+ const store = options.local?.store;
104
+ return store instanceof ScriptedLocalAgentStore ? store.workspaceRef : undefined;
105
+ }
106
+
107
+ /**
108
+ * The `@cursor/sdk/sqlite` store the adapter opens per session, holding
109
+ * nothing: the scripted agents carry their own state, so the store only has
110
+ * to be the thing `Agent.create` / `Agent.resume` are handed and the thing
111
+ * `releaseSession` / `shutdown` dispose. `open` and `dispose` are recorded on
112
+ * the bound {@link ScriptedCursorSdk} for lifetime assertions.
113
+ */
114
+ export class ScriptedLocalAgentStore {
115
+ disposeCalls = 0;
116
+
117
+ constructor(
118
+ readonly workspaceRef: string,
119
+ readonly stateRoot: string,
120
+ ) {}
121
+
122
+ static async open(options: SqliteLocalAgentStoreOptions): Promise<ScriptedLocalAgentStore> {
123
+ const store = new ScriptedLocalAgentStore(options.workspaceRef, options.stateRoot ?? "");
124
+ current().stores.push(store);
125
+ return store;
126
+ }
127
+
128
+ async dispose(): Promise<void> {
129
+ this.disposeCalls++;
130
+ }
95
131
  }
96
132
 
97
133
  export class ScriptedCursorSdk {
98
134
  readonly resolutions: RecordedResolution[] = [];
99
- readonly archived: string[] = [];
135
+ /** Every store `SqliteLocalAgentStore.open` handed out, in order. */
136
+ readonly stores: ScriptedLocalAgentStore[] = [];
100
137
  private nextCreate = 0;
101
138
  private createFailurePending: boolean;
102
139
  private readonly byId = new Map<string, ScriptedCursorAgent>();
@@ -145,10 +182,6 @@ export class ScriptedCursorSdk {
145
182
  return agent;
146
183
  }
147
184
 
148
- archive(agentId: string): void {
149
- this.archived.push(agentId);
150
- }
151
-
152
185
  listModels(): readonly ModelListItem[] {
153
186
  return this.options.catalog;
154
187
  }
@@ -242,7 +275,6 @@ export function scriptedCursorSdkModule(): Record<string, unknown> {
242
275
  create: async (options: AgentOptions): Promise<SDKAgent> => current().create(options),
243
276
  resume: async (agentId: string, options?: Partial<AgentOptions>): Promise<SDKAgent> =>
244
277
  current().resume(agentId, options),
245
- archive: async (agentId: string): Promise<void> => current().archive(agentId),
246
278
  },
247
279
  Cursor: {
248
280
  models: {
@@ -252,3 +284,27 @@ export function scriptedCursorSdkModule(): Record<string, unknown> {
252
284
  CursorSdkError: ScriptedCursorSdkError,
253
285
  };
254
286
  }
287
+
288
+ /**
289
+ * The factory a test passes to `vi.mock("@cursor/sdk/sqlite", ...)`, beside
290
+ * the one above:
291
+ *
292
+ * ```ts
293
+ * vi.mock("@cursor/sdk/sqlite", async () =>
294
+ * (await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSqliteModule(),
295
+ * );
296
+ * ```
297
+ *
298
+ * The one export the runner reads from that entry (`session-store.ts`). The
299
+ * class is exported under the SDK's name so `session-store.ts`'s dynamic
300
+ * import destructures it unchanged; its type is the SDK's, which is why
301
+ * {@link ScriptedLocalAgentStore} carries `workspaceRef`, `stateRoot` and
302
+ * `dispose()` — the members the runner touches — and nothing else.
303
+ */
304
+ export function scriptedCursorSqliteModule(): Record<string, unknown> {
305
+ return {
306
+ SqliteLocalAgentStore: ScriptedLocalAgentStore satisfies {
307
+ open(options: SqliteLocalAgentStoreOptions): Promise<Pick<SqliteLocalAgentStore, "workspaceRef" | "stateRoot" | "dispose">>;
308
+ },
309
+ };
310
+ }
@@ -1,5 +1,6 @@
1
1
  /**
2
- * @regression file-hitl-phase0 — pins file-edit HITL fix #6 (see _projects/2026-06/20260630.01.file-change-hitl-redesign/tasks/T01_3_regression-manifest.md)
2
+ * @regression file-hitl-phase0 — pins content-exact approval identity: approving
3
+ * one edit never lets a DIFFERENT edit to the same path ride the grant.
3
4
  *
4
5
  * Unit tests for the Cursor-harness HITL approval gate logic.
5
6
  *
@@ -1,5 +1,6 @@
1
1
  /**
2
- * @regression file-hitl-phase0 — pins file-edit HITL fix #6 (see _projects/2026-06/20260630.01.file-change-hitl-redesign/tasks/T01_3_regression-manifest.md)
2
+ * @regression file-hitl-phase0 — pins content-exact approval identity: approving
3
+ * one edit never lets a DIFFERENT edit to the same path ride the grant.
3
4
  *
4
5
  * Resume-grant identity round-trip — the H1 lock.
5
6
  *
@@ -21,7 +22,7 @@
21
22
  * - the resume grant via {@link buildApprovalGrants} -> parseArgs(argsPreview)
22
23
  * (the JSON-string preview only).
23
24
  * They agree today only because both derive from the same stream `event.args`.
24
- * This suite drives the REAL stream path ({@link buildToolCallProto}) so any
25
+ * This suite drives the REAL stream path (the translator into the builder) so any
25
26
  * future change that lets the dual path diverge fails here, loudly, per category.
26
27
  *
27
28
  * Deterministic; no Cursor API key, no bash. The hook-side half of the equality
@@ -42,11 +43,9 @@ import {
42
43
  } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
43
44
  import type { SDKMessage } from "@cursor/sdk";
44
45
 
45
- import {
46
- buildToolCallProto,
47
- reconcileDeniedToolCalls,
48
- toolCallIdentityToken,
49
- } from "../message-translator.js";
46
+ import { reconcileDeniedToolCalls } from "../boundary-rows.js";
47
+ import { builderOver, foldCursorEvents } from "../__test-utils__/fold.js";
48
+ import { toolCallIdentityToken } from "../approval-state.js";
50
49
  import {
51
50
  buildApprovalGrants,
52
51
  buildApprovalState,
@@ -96,7 +95,7 @@ function mcpEvent(
96
95
  * and return the two identities that must be equal: the token the hook recorded
97
96
  * when it denied the gated call, and the grant token a resume mints after the
98
97
  * user approves it. Mirrors the activity's real sequence:
99
- * buildToolCallProto (stream) -> deny overlay (reconcileDeniedToolCalls) ->
98
+ * translator + builder (stream) -> deny overlay (reconcileDeniedToolCalls) ->
100
99
  * persist APPROVE -> reconstructAdjudicatedApprovals -> buildApprovalGrants.
101
100
  */
102
101
  async function roundTrip(event: Extract<SDKMessage, { type: "tool_call" }>): Promise<{
@@ -105,7 +104,7 @@ async function roundTrip(event: Extract<SDKMessage, { type: "tool_call" }>): Pro
105
104
  resumeStateToken: string | undefined;
106
105
  grant: ApprovalGrant;
107
106
  }> {
108
- const tc = buildToolCallProto(event);
107
+ const tc = foldCursorEvents([event]).rows()[0];
109
108
 
110
109
  // The gated turn: the hook denies the call, recording its identity token. The
111
110
  // runner's overlay (reconcileDeniedToolCalls) flips the same call to
@@ -120,7 +119,8 @@ async function roundTrip(event: Extract<SDKMessage, { type: "tool_call" }>): Pro
120
119
  toolCalls: [tc],
121
120
  });
122
121
  const ledger: DeniedLedgerEntry[] = [{ toolName: tc.name, token: denialToken }];
123
- const denied = await reconcileDeniedToolCalls([msg], ledger);
122
+ const messages: AgentMessage[] = [msg];
123
+ const denied = await reconcileDeniedToolCalls(messages, builderOver(messages), ledger);
124
124
  expect(denied, "the overlay must match the denial token and surface the gate").toHaveLength(1);
125
125
 
126
126
  // The user approves; the backend persists the decision on the tool call.
@@ -130,7 +130,6 @@ async function roundTrip(event: Extract<SDKMessage, { type: "tool_call" }>): Pro
130
130
  // transcript (pending_approvals is already cleared by this point) and mint the
131
131
  // grants the next turn's hook reads. The content digest threads through so the
132
132
  // grant reproduces the content-exact denial identity.
133
- const messages: AgentMessage[] = [msg];
134
133
  const { pendingApprovals, decisions, contentDigests } = reconstructAdjudicatedApprovals(messages);
135
134
  const grants = buildApprovalGrants(pendingApprovals, decisions, contentDigests);
136
135
  expect(grants, "an approved tool must yield exactly one grant").toHaveLength(1);
@@ -234,12 +233,8 @@ describe("Cursor resume-grant identity round-trip (H1 lock)", () => {
234
233
  // The exact bug this change fixes: approving the rename must NOT authorize
235
234
  // the TODO edit. They share a path (same coarse token) but differ in content,
236
235
  // so the content-exact identity distinguishes them.
237
- const rename = buildToolCallProto(
238
- builtInEvent("c1", "edit", { path: "/work/notes.md", old_string: "Planton Cloud", new_string: "Planton" }),
239
- );
240
- const todo = buildToolCallProto(
241
- builtInEvent("c2", "edit", { path: "/work/notes.md", old_string: "", new_string: "## TODO\n" }),
242
- );
236
+ const rename = foldCursorEvents([builtInEvent("c1", "edit", { path: "/work/notes.md", old_string: "Planton Cloud", new_string: "Planton" })]).rows()[0];
237
+ const todo = foldCursorEvents([builtInEvent("c2", "edit", { path: "/work/notes.md", old_string: "", new_string: "## TODO\n" })]).rows()[0];
243
238
  const renameToken = toolCallIdentityToken(rename);
244
239
  const todoToken = toolCallIdentityToken(todo);
245
240
 
@@ -252,9 +247,7 @@ describe("Cursor resume-grant identity round-trip (H1 lock)", () => {
252
247
  );
253
248
  // Re-issuing the SAME rename content reproduces its identity (identical
254
249
  // re-attempt is allowed; a drifted one re-gates).
255
- const renameAgain = buildToolCallProto(
256
- builtInEvent("c3", "edit", { path: "/work/notes.md", old_string: "Planton Cloud", new_string: "Planton" }),
257
- );
250
+ const renameAgain = foldCursorEvents([builtInEvent("c3", "edit", { path: "/work/notes.md", old_string: "Planton Cloud", new_string: "Planton" })]).rows()[0];
258
251
  expect(toolCallIdentityToken(renameAgain)).toBe(renameToken);
259
252
  });
260
253
 
@@ -263,7 +256,7 @@ describe("Cursor resume-grant identity round-trip (H1 lock)", () => {
263
256
  event: Extract<SDKMessage, { type: "tool_call" }>,
264
257
  action: ApprovalAction,
265
258
  ): AgentMessage {
266
- const tc = buildToolCallProto(event);
259
+ const tc = foldCursorEvents([event]).rows()[0];
267
260
  tc.status = ToolCallStatus.TOOL_CALL_WAITING_APPROVAL;
268
261
  tc.requiresApproval = true;
269
262
  tc.approvalAction = action;
@@ -544,7 +544,7 @@ describe("attachments on a resumed turn (T04 — the mid-session WhatsApp case)"
544
544
  ],
545
545
  }),
546
546
  );
547
- // The size precedes the disclosure (the shared line, S3 M5 Q-M5-3).
547
+ // The size precedes the disclosure (the shared line, since #1096).
548
548
  expect(prompt).toContain(
549
549
  "- `.stigmer/inputs/report-2.pdf` (1024 bytes) (renamed from duplicate 'report.pdf')",
550
550
  );
@@ -778,8 +778,8 @@ describe("buildReinvocationPrompt", () => {
778
778
  expect(prompt).toContain("Continue the rest of the task");
779
779
  });
780
780
 
781
- it("names a REJECTED action as a refusal, apart from the skipped ones, and still continues the task (stigmer#197; S3 M1)", () => {
782
- // A REJECT denies the tool and the run continues; before S3 M1 the
781
+ it("names a REJECTED action as a refusal, apart from the skipped ones, and still continues the task (stigmer#197)", () => {
782
+ // A REJECT denies the tool and the run continues; before #1096 the
783
783
  // runtime failed the reinvocation before this prompt was ever built, so
784
784
  // the prompt had no REJECT arm.
785
785
  const decisions = new Map<string, ApprovalAction>([
@@ -1,5 +1,6 @@
1
1
  /**
2
- * @regression file-hitl-phase0 — pins file-edit HITL fix #6 (see _projects/2026-06/20260630.01.file-change-hitl-redesign/tasks/T01_3_regression-manifest.md)
2
+ * @regression file-hitl-phase0 — pins content-exact approval identity: approving
3
+ * one edit never lets a DIFFERENT edit to the same path ride the grant.
3
4
  *
4
5
  * Slice D — the Cursor grant token / fingerprint as the substrate-coarsened
5
6
  * projection of the shared canonical action.