@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
@@ -0,0 +1,693 @@
1
+ /**
2
+ * TranscriptBuilder — folds `TranscriptEvent`s into the transcript half of
3
+ * the AgentExecutionStatus proto it is handed: messages, tool-call rows and
4
+ * their approval status, sub-agent rows, todos, artifacts, write-backs.
5
+ *
6
+ * The one transcript builder, for every harness (#1097). It
7
+ * was the native harness's `V3StatusBuilder` (the one builder there since
8
+ * #1096 retired the v2 `StatusBuilder`), promoted here on 2026-09-14
9
+ * unchanged and then cut engine-neutral one rule per commit:
10
+ * it reads no engine envelope, decides nothing about approval,
11
+ * and knows no engine's tool names or namespace grammar — every engine
12
+ * fact reaches it as a translator's output, on one union. The Cursor
13
+ * harness feeds it through a translator; the runtime constructs it once
14
+ * per turn and hands it to every adapter as `TurnSink.transcript`, so
15
+ * a transcript row has exactly one way into the status — a source-walking
16
+ * fence, `harness/__tests__/transcript-writers.test.ts`, refuses a second.
17
+ *
18
+ * ONE set of handlers over ONE scope shape: every handler takes
19
+ * the scope's {@link Transcript} — the root's over `status.messages`, or a
20
+ * sub-agent's over its row's — from `TranscriptState`, so a sub-agent's
21
+ * transcript is folded by exactly the rules the root's is. Until #1097 the
22
+ * sub-agents' half was a second module (`SubAgentTracker`) with its own copy
23
+ * of every handler, differing only in which array it pushed into — the
24
+ * memo's third copy of the folding rule, and the one whose namespace filter
25
+ * differed from the root's by one segment (found in #1096: the root
26
+ * filed text under `model_request:<uuid>` and looked the tool's parent up
27
+ * under `""`, so every native tool row sat on an empty message after its
28
+ * text). With scope a single value per transcript, that class of miss
29
+ * cannot exist.
30
+ *
31
+ * The rules this builder owns, each with an arm in
32
+ * `harness/transcript/__tests__/builder.test.ts` and the harness whose rule
33
+ * it generalises in parentheses:
34
+ *
35
+ * - A row per `callId`, indexed over the status as handed and over what
36
+ * {@link seed} appends (a reinvocation's prior rows, indexed by the same
37
+ * routine, so a builder born before the seed is no different from one
38
+ * born after it), reconciled in place on a re-emitted start — an UNSETTLED row becomes
39
+ * RUNNING (a WAITING row on native's durable-checkpoint resume; an
40
+ * INTERRUPTED row on a recovery replay, the enum's supersede rule) and
41
+ * takes the args and preview it lacked — never duplicated. Every row
42
+ * with args carries `argsPreview`, elided and redacted, salient fields
43
+ * verbatim. A finish or an error is an upsert: status
44
+ * monotonic, `completedAt` once, a non-empty result or message
45
+ * overwrites, an empty one never clears; a re-emit that
46
+ * changes nothing forces no persist; a fact the harness
47
+ * observed earlier and delivers later stamps its own instant
48
+ * (`observedAt`); an output chunk for a settled row is stale
49
+ * and dropped — the completion's result is the whole output.
50
+ * - The AI-message boundary (native's own rule, made correct by
51
+ * scoping): a tool row attaches to the scope's current AI message — the
52
+ * latest with text, the seed's last AI message over a seeded transcript
53
+ * — and to a new empty one only when the scope has none.
54
+ * - A THINKING row per `runId`, a text message per `runId`; a
55
+ * new run closes the previous message's streaming flag, and a run's
56
+ * finish closes both its text and its thinking.
57
+ * - A sub-agent row per `subAgentId`, opened by `sub_agent_started`,
58
+ * closed COMPLETED/FAILED by `sub_agent_finished/failed` with its
59
+ * transcript's streaming flags cleared; a known id is never re-opened.
60
+ * CANCELLED is not this builder's: `shared/subagent-rows.ts`
61
+ * `cancelInProgressSubAgentProtos` is the one home of that transition.
62
+ * - `approval_proposed` is the one place a row is ever WAITING: a known
63
+ * row REOPENS — WAITING, the outcome fields cleared,
64
+ * `approvalRequestedAt` stamped once, the proposal's args and preview
65
+ * taken when carried (Cursor's `markWaitingApproval` + `applyGateInput`);
66
+ * an unknown call gets a WAITING row on the scope's current AI message,
67
+ * the text that proposed it (native's post-stream seed, before #1097 a new
68
+ * empty message of its own). Either way {@link awaitingApproval} is set.
69
+ * - `system_note` is a SYSTEM message in the scope, in the harness's
70
+ * voice; it hosts no rows and moves no boundary.
71
+ * - A completed `ToolKind.TODO` call in the ROOT scope is projected into
72
+ * `status.todos` through the shared `applyTodoUpdate`, a full replace
73
+ * unless the call's args say `merge: true` (the row stays — the
74
+ * clients filter it); a sub-agent's is not.
75
+ * - `finalize()` clears every streaming flag in every scope.
76
+ * - Artifacts upsert by `sandboxPath`/`contentHash`, write-backs by
77
+ * `workspaceEntryName`: the inline publisher and the write-back
78
+ * coordinator register theirs here, each through the one-method view it
79
+ * declares for itself (`ArtifactSink`, `WriteBackSink`), which this class
80
+ * satisfies by shape.
81
+ * - {@link dirty} is set by every discrete change above and by nothing a
82
+ * token delta does; the adapter's loop reads it and clears it with
83
+ * {@link markPersisted} as it requests the persist.
84
+ *
85
+ * What this builder deliberately does NOT write, and who does (the adapter
86
+ * contract's field ownership, `harness/types.ts` `TurnSink`): the phase,
87
+ * `startedAt`, `streamingUsage` and the epilogue's plan artifact are the
88
+ * turn runtime's (the plan artifact supersedes by its own name rule, which
89
+ * is the plan's knowledge, not the transcript's). A row left
90
+ * WAITING_APPROVAL is reported as the {@link awaitingApproval} fact and the
91
+ * caller decides what that means for the turn — a fact only
92
+ * `approval_proposed` produces, because a call that has
93
+ * STARTED is never parked at creation. Usage never passes
94
+ * through here: the native loop reads it off the wire (`usageOf`) and
95
+ * prices it into the sink, the Cursor loop reads its own from the SDK.
96
+ */
97
+ import { create } from "@bufbuild/protobuf";
98
+ import { AgentMessageSchema, ToolCallSchema, } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
99
+ import { SubAgentExecutionSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/subagent_pb";
100
+ import { MessageType, SubAgentStatus, ToolCallStatus, ToolCallStreamingSource, ToolKind, } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
101
+ import { POLICY_ENGINE_VERSION, toProtoPolicySource } from "../../shared/approval-policy.js";
102
+ import { SALIENT_ARG_FIELDS, buildElidedArgsPreview } from "../../shared/args-preview.js";
103
+ import { classifyTool } from "../../shared/tool-kind.js";
104
+ import { applyTodoUpdate } from "../../shared/todos.js";
105
+ import { utcTimestamp } from "../../shared/status.js";
106
+ import { TranscriptState } from "./state.js";
107
+ export class TranscriptBuilder {
108
+ executionId;
109
+ state;
110
+ _dirty = false;
111
+ _awaitingApproval = false;
112
+ /**
113
+ * Builds INTO `status`, by reference: its `messages`, `subAgentExecutions`
114
+ * and every sub-agent row's `messages` are the arrays indexed and pushed
115
+ * into, never replaced, so a caller that wraps the same status (the
116
+ * runtime's chokepoint, a settle amending rows by identity) keeps seeing
117
+ * every row. Rows already on the status are indexed here; rows a
118
+ * reinvocation carries over arrive later through {@link seed}, indexed by
119
+ * the same routine, so a re-driven event reconciles onto them either way.
120
+ *
121
+ * The builder hands nothing back. A reader holds the status it built the
122
+ * builder over — `TurnSink.status` in production, the test's own in a
123
+ * test — so the transcript has one read handle and one write handle, and
124
+ * no second spelling of either.
125
+ */
126
+ constructor(executionId, status) {
127
+ this.executionId = executionId;
128
+ this.state = new TranscriptState(status);
129
+ }
130
+ /**
131
+ * Append a reinvocation's persisted transcript — messages, sub-agent
132
+ * rows, artifacts, write-backs, todos — and index it, so the turn that
133
+ * follows APPENDS onto prior history and a re-issued call reconciles onto
134
+ * its seeded row instead of duplicating it. The runtime calls this once,
135
+ * in its reinvocation phase, before any harness runs; the reasons every
136
+ * collection is seeded are that phase's (`harness/turn-context.ts`
137
+ * `seedFromPersistedStatus`). Seeded rows are last turn's facts: this sets
138
+ * neither {@link dirty} nor {@link awaitingApproval}.
139
+ */
140
+ seed(persisted) {
141
+ this.state.seed(persisted);
142
+ }
143
+ /**
144
+ * True once a row this turn was left WAITING_APPROVAL: the engine has
145
+ * interrupted (or the harness's boundary parked the call) and the turn
146
+ * should end awaiting a decision. A fact about the transcript, not a phase
147
+ * — the caller owns the phase. No `tool_started` sets it (a started call
148
+ * is running); `approval_proposed` does.
149
+ */
150
+ get awaitingApproval() {
151
+ return this._awaitingApproval;
152
+ }
153
+ /**
154
+ * True once a discrete, user-visible change has landed since the last
155
+ * persist — a row started or settled, a sub-agent opened or closed, an
156
+ * artifact or write-back registered, a note appended; never a token
157
+ * delta, which rides the streaming cadence. The one fact the adapter's
158
+ * persist decision reads (`shared/persist-decision.ts`); the adapter
159
+ * clears it with {@link markPersisted} as it requests the write, so a
160
+ * change that lands after the write started dirties the next one.
161
+ */
162
+ get dirty() {
163
+ return this._dirty;
164
+ }
165
+ markPersisted() {
166
+ this._dirty = false;
167
+ }
168
+ /** Fold one canonical event into the transcript. Never throws: a handler's error is logged and the stream goes on. */
169
+ apply(event) {
170
+ try {
171
+ switch (event.kind) {
172
+ case "sub_agent_started":
173
+ this.openSubAgent(event);
174
+ return;
175
+ case "sub_agent_finished":
176
+ this.closeSubAgent(event);
177
+ return;
178
+ case "sub_agent_failed":
179
+ this.failSubAgent(event);
180
+ return;
181
+ default:
182
+ break;
183
+ }
184
+ const scope = this.state.scope(event.subAgentId);
185
+ if (!scope) {
186
+ throw new Error(`event for unknown sub-agent ${event.subAgentId}`);
187
+ }
188
+ switch (event.kind) {
189
+ case "message_start":
190
+ this.handleMessageStart(scope, event.runId);
191
+ break;
192
+ case "text_delta":
193
+ this.appendTextContent(scope, event.runId, event.text);
194
+ break;
195
+ case "reasoning_delta":
196
+ this.appendThinkingContent(scope, event.runId, event.text);
197
+ break;
198
+ case "message_finish":
199
+ this.handleMessageFinish(scope, event.runId);
200
+ break;
201
+ case "tool_started":
202
+ this.handleToolStarted(scope, event);
203
+ break;
204
+ case "tool_arg_delta":
205
+ this.handleToolArgDelta(scope, event.callId, event.argsChunk);
206
+ break;
207
+ case "tool_output_delta":
208
+ this.handleToolOutputDelta(scope, event.callId, event.delta);
209
+ break;
210
+ case "tool_finished":
211
+ this.handleToolFinished(scope, event.callId, event.result, event.observedAt);
212
+ break;
213
+ case "tool_error":
214
+ this.handleToolError(scope, event.callId, event.message, event.observedAt);
215
+ break;
216
+ case "approval_proposed":
217
+ this.handleApprovalProposed(scope, event);
218
+ break;
219
+ case "system_note":
220
+ this.appendSystemNote(scope, event.text);
221
+ break;
222
+ default: {
223
+ const exhaustive = event;
224
+ throw new Error(`unknown transcript event ${String(exhaustive.kind)}`);
225
+ }
226
+ }
227
+ }
228
+ catch (err) {
229
+ console.error(`[TranscriptBuilder] Event handler error: execution=${this.executionId} kind=${event.kind}: ${err}`);
230
+ }
231
+ }
232
+ /**
233
+ * Every streaming flag off, in every scope — messages and rows. What a
234
+ * turn owes the transcript when its stream ends, however it ended: a
235
+ * stopped turn's in-flight message must not persist as still streaming.
236
+ * The sub-agent rows' own CANCELLED transition is the caller's, through
237
+ * the shared `cancelInProgressSubAgentProtos`.
238
+ */
239
+ finalize() {
240
+ for (const transcript of this.state.transcripts())
241
+ finalizeStreaming(transcript);
242
+ }
243
+ // ── Artifact & WriteBack ───────────────────────────────────────────
244
+ addArtifact(artifact) {
245
+ const artifacts = this.state.proto.artifacts;
246
+ const idx = artifacts.findIndex(a => a.sandboxPath === artifact.sandboxPath);
247
+ if (idx >= 0) {
248
+ if (artifacts[idx].contentHash !== artifact.contentHash) {
249
+ artifacts[idx] = artifact;
250
+ this._dirty = true;
251
+ }
252
+ return;
253
+ }
254
+ artifacts.push(artifact);
255
+ this._dirty = true;
256
+ }
257
+ addWriteBack(wb) {
258
+ const backs = this.state.proto.workspaceWriteBacks;
259
+ const idx = backs.findIndex(b => b.workspaceEntryName === wb.workspaceEntryName);
260
+ if (idx >= 0) {
261
+ backs[idx] = wb;
262
+ }
263
+ else {
264
+ backs.push(wb);
265
+ }
266
+ this._dirty = true;
267
+ }
268
+ // ── Sub-Agent Rows ─────────────────────────────────────────────────
269
+ openSubAgent(event) {
270
+ // A seeded row re-announced by a replayed engine (the memory-checkpointer
271
+ // re-drives the whole graph): the row and its transcript already exist.
272
+ if (this.state.subAgent(event.subAgentId))
273
+ return;
274
+ const row = create(SubAgentExecutionSchema, {
275
+ id: event.subAgentId,
276
+ name: event.name,
277
+ subject: event.subject,
278
+ input: event.input,
279
+ status: SubAgentStatus.SUB_AGENT_IN_PROGRESS,
280
+ startedAt: utcTimestamp(),
281
+ });
282
+ this.state.openSubAgent(row);
283
+ this._dirty = true;
284
+ }
285
+ closeSubAgent(event) {
286
+ const scope = this.state.subAgent(event.subAgentId);
287
+ if (!scope)
288
+ return;
289
+ scope.row.status = SubAgentStatus.SUB_AGENT_COMPLETED;
290
+ scope.row.completedAt = utcTimestamp();
291
+ if (event.output !== undefined)
292
+ scope.row.output = event.output;
293
+ finalizeStreaming(scope.transcript);
294
+ this._dirty = true;
295
+ }
296
+ failSubAgent(event) {
297
+ const scope = this.state.subAgent(event.subAgentId);
298
+ if (!scope)
299
+ return;
300
+ scope.row.status = SubAgentStatus.SUB_AGENT_FAILED;
301
+ scope.row.completedAt = utcTimestamp();
302
+ scope.row.error = event.error;
303
+ finalizeStreaming(scope.transcript);
304
+ this._dirty = true;
305
+ }
306
+ // ── Message Handlers ───────────────────────────────────────────────
307
+ handleMessageStart(scope, runId) {
308
+ // Record the run for the message boundary but do NOT create the AI
309
+ // message yet: it is created lazily on the first text_delta, so a
310
+ // THINKING row that streams first sits before the text it precedes.
311
+ if (scope.lastRunId && scope.lastRunId !== runId && scope.currentAiMessage) {
312
+ scope.currentAiMessage.isStreaming = false;
313
+ }
314
+ scope.lastRunId = runId;
315
+ }
316
+ handleMessageFinish(scope, runId) {
317
+ // A finished run's text AND its thinking are finished (Cursor closes
318
+ // both when a tool call ends the segment). Before #1097 only the
319
+ // text closed here and the THINKING row spun until `finalize()` — a live
320
+ // spinner on a block the model had left, on both harnesses.
321
+ const msg = scope.messagesByRun.get(runId);
322
+ if (msg) {
323
+ msg.isStreaming = false;
324
+ }
325
+ const thinking = scope.messagesByRun.get(thinkingKeyOf(runId));
326
+ if (thinking) {
327
+ thinking.isStreaming = false;
328
+ }
329
+ }
330
+ appendTextContent(scope, runId, text) {
331
+ const msg = this.ensureAiMessage(scope, runId);
332
+ msg.content += text;
333
+ msg.isStreaming = true;
334
+ }
335
+ appendThinkingContent(scope, runId, text) {
336
+ // One THINKING row per run, keyed apart from the run's text so
337
+ // the two never share a message.
338
+ const thinkingKey = thinkingKeyOf(runId);
339
+ const existingMsg = scope.messagesByRun.get(thinkingKey);
340
+ if (existingMsg && existingMsg.type === MessageType.MESSAGE_THINKING) {
341
+ existingMsg.content += text;
342
+ existingMsg.isStreaming = true;
343
+ return;
344
+ }
345
+ const msg = create(AgentMessageSchema, {
346
+ type: MessageType.MESSAGE_THINKING,
347
+ content: text,
348
+ timestamp: utcTimestamp(),
349
+ isStreaming: true,
350
+ });
351
+ scope.messages.push(msg);
352
+ scope.messagesByRun.set(thinkingKey, msg);
353
+ }
354
+ // ── Tool Handlers ──────────────────────────────────────────────────
355
+ handleToolStarted(scope, event) {
356
+ const { callId, name, input } = event;
357
+ // A re-emitted start reconciles onto the existing row — never a duplicate,
358
+ // never a second gate. Keyed by the provider's tool_call_id, so this is an
359
+ // exact match (no name heuristics). Two shapes reach here: the durable
360
+ // checkpoint re-emitting a seeded WAITING call now that approval is granted
361
+ // (native's resume; the runtime's `seedFromPersistedStatus`), and a
362
+ // recovery replaying a call the server had marked INTERRUPTED when the
363
+ // execution terminalized with it in flight (the enum's supersede rule; the
364
+ // Cursor accumulator's merge). Either way an UNSETTLED row becomes RUNNING
365
+ // (before #1097 only WAITING flipped); a settled one keeps
366
+ // its outcome. Args it lacked are filled and previewed, once.
367
+ const existing = scope.toolCalls.get(callId);
368
+ if (existing) {
369
+ if (!isSettled(existing.status)) {
370
+ existing.status = ToolCallStatus.TOOL_CALL_RUNNING;
371
+ }
372
+ if (Object.keys(input).length > 0) {
373
+ if (!existing.args)
374
+ existing.args = input;
375
+ if (!existing.argsPreview)
376
+ stampArgsPreview(existing, input);
377
+ }
378
+ this._dirty = true;
379
+ return;
380
+ }
381
+ // The message boundary: the row joins the message whose text
382
+ // proposed it — the scope's current AI message — and gets an empty one
383
+ // only when the scope has no message yet.
384
+ const parentMsg = scope.currentAiMessage ?? this.ensureAiMessageForToolCall(scope);
385
+ // A started call is RUNNING, gated or not: a gated call that has started
386
+ // runs until the harness's boundary parks it through `approval_proposed`
387
+ // (Cursor), and on native a held call never starts at all — the engine
388
+ // interrupts before the tool runs and the post-stream seed proposes it.
389
+ // The builder writes the gate's word it is told and decides nothing
390
+ // about approval.
391
+ const tc = create(ToolCallSchema, {
392
+ id: callId,
393
+ name,
394
+ status: ToolCallStatus.TOOL_CALL_RUNNING,
395
+ startedAt: utcTimestamp(),
396
+ });
397
+ if (Object.keys(input).length > 0) {
398
+ tc.args = input;
399
+ stampArgsPreview(tc, input);
400
+ }
401
+ if (event.mcpServerSlug) {
402
+ tc.mcpServerSlug = event.mcpServerSlug;
403
+ }
404
+ // Classify after mcpServerSlug is set so MCP tools resolve correctly.
405
+ tc.toolKind = classifyTool(tc.name, tc.mcpServerSlug);
406
+ // Authorization provenance — which policy layer governs the call — stamped
407
+ // in the same spot as tool_kind, for every observed call the translator
408
+ // could attribute (gated or auto-approved), so the persisted record is
409
+ // auditable and the UI can explain the gate. Absent provenance leaves the
410
+ // field at UNSPECIFIED, like an unclassified tool_kind. A gated call is
411
+ // re-seeded on reinvocation (the runtime's wide seed) with the same source
412
+ // carried through the interrupt.
413
+ if (event.provenance !== undefined) {
414
+ tc.approvalPolicySource = toProtoPolicySource(event.provenance);
415
+ tc.policyEngineVersion = POLICY_ENGINE_VERSION;
416
+ }
417
+ // The gate's word: the row says it is gated and what the card will ask;
418
+ // `approvalRequestedAt` is stamped when the boundary actually parks it
419
+ // (`approval_proposed`, or a gated row's `tool_error`), never here.
420
+ if (event.gate) {
421
+ tc.requiresApproval = true;
422
+ tc.approvalMessage = event.gate.message;
423
+ }
424
+ parentMsg.toolCalls.push(tc);
425
+ scope.toolCalls.set(callId, tc);
426
+ this._dirty = true;
427
+ }
428
+ handleToolFinished(scope, callId, result, observedAt) {
429
+ const tc = scope.toolCalls.get(callId);
430
+ if (!tc)
431
+ return;
432
+ // An UPSERT, not an overwrite (Cursor's `mergeToolCallEvent`):
433
+ // the status advances monotonically — a settled row never regresses;
434
+ // `completedAt` is stamped once; only a non-empty result overwrites, so a
435
+ // completion that carries none never wipes the output an earlier one
436
+ // did. Two completions per call is the Cursor shape after stigmer#1053
437
+ // (the SDK's timing delta precedes the stream's completion); on native
438
+ // there is one, and the rules read as the plain write they replace.
439
+ //
440
+ // Store the faithful result; bounding the gRPC payload is owned solely by
441
+ // the persist chokepoint (offload + enforce in status.ts/status-offload.ts).
442
+ // Truncating here would corrupt binary content (e.g. a screenshot's base64)
443
+ // before offload can lift it into a renderable ToolCallOutputRef.
444
+ //
445
+ // A completion that changes nothing — a settled row re-completed with no
446
+ // new result — forces no persist (Cursor's "a redundant
447
+ // terminal re-emit is noise, not a state change"). On Cursor every call
448
+ // completes twice (the delta, then the stream), and the second carries the
449
+ // result, so the flush the UI needs still happens exactly once.
450
+ const wasSettled = isSettled(tc.status);
451
+ const resultChanged = !!result && result !== tc.result;
452
+ if (!wasSettled)
453
+ tc.status = ToolCallStatus.TOOL_CALL_COMPLETED;
454
+ // The instant the harness OBSERVED the completion when it delivers it
455
+ // later (Cursor's queued delta); otherwise now.
456
+ if (!tc.completedAt)
457
+ tc.completedAt = observedAt ?? utcTimestamp();
458
+ if (resultChanged)
459
+ tc.result = result;
460
+ stopStreaming(tc);
461
+ scope.argBuffers.delete(callId);
462
+ if (wasSettled && !resultChanged)
463
+ return;
464
+ // Project a completed to-do write into status.todos. deepagents' write_todos
465
+ // runs its state-mutating Command when the tool node COMPLETES, so we mirror
466
+ // it here (not at tool-start) — a call cancelled before finishing correctly
467
+ // projects nothing. Keyed on the harness-agnostic ToolKind.TODO (stamped at
468
+ // tool-start) and fed by the same shared mapper every harness uses; the
469
+ // call's own `merge` flag decides replace-or-merge (Cursor's `updateTodos`
470
+ // sets it; deepagents never does, so native stays a full replace);
471
+ // a sub-agent's list is its own, never the execution's. The tool
472
+ // call itself stays in messages (the client filters ToolKind.TODO from the
473
+ // thread).
474
+ if (scope === this.state.root && tc.toolKind === ToolKind.TODO) {
475
+ applyTodoUpdate(this.state.proto.todos, tc.args?.todos, { merge: tc.args?.merge === true });
476
+ }
477
+ this._dirty = true;
478
+ }
479
+ handleToolError(scope, callId, message, observedAt) {
480
+ const tc = scope.toolCalls.get(callId);
481
+ if (!tc)
482
+ return;
483
+ // The same upsert as a finish. A gated row that fails is the
484
+ // Cursor boundary's shape — the hook denied the call and the stream
485
+ // reports `error`; the boundary parks it after the stream — so the
486
+ // moment approval became due is stamped here if nothing stamped it yet.
487
+ const wasSettled = isSettled(tc.status);
488
+ const messageChanged = !!message && message !== tc.error;
489
+ const at = observedAt ?? utcTimestamp();
490
+ if (!wasSettled)
491
+ tc.status = ToolCallStatus.TOOL_CALL_FAILED;
492
+ if (!tc.completedAt)
493
+ tc.completedAt = at;
494
+ if (messageChanged)
495
+ tc.error = message;
496
+ if (tc.requiresApproval && !tc.approvalRequestedAt)
497
+ tc.approvalRequestedAt = at;
498
+ stopStreaming(tc);
499
+ scope.argBuffers.delete(callId);
500
+ // The same no-change rule as a finish.
501
+ if (wasSettled && !messageChanged)
502
+ return;
503
+ this._dirty = true;
504
+ }
505
+ handleToolArgDelta(scope, callId, argsChunk) {
506
+ const tc = scope.toolCalls.get(callId);
507
+ if (!tc)
508
+ return;
509
+ const buffer = (scope.argBuffers.get(callId) ?? "") + argsChunk;
510
+ scope.argBuffers.set(callId, buffer);
511
+ try {
512
+ tc.args = JSON.parse(buffer);
513
+ }
514
+ catch {
515
+ // Partial JSON — will parse on next chunk or tool-finished
516
+ }
517
+ }
518
+ handleToolOutputDelta(scope, callId, delta) {
519
+ const tc = scope.toolCalls.get(callId);
520
+ if (!tc)
521
+ return;
522
+ // A chunk for a row that has already settled is stale: the completion's
523
+ // result IS the whole output, and appending would double it (Cursor's
524
+ // delta channel and stream can deliver the output's
525
+ // chunks and the completion in one loop window, completion first).
526
+ if (isSettled(tc.status))
527
+ return;
528
+ // Output arriving live: the row streams its OUTPUT (Cursor's
529
+ // enricher), so the client can show the partial result as it grows;
530
+ // the finish, or `finalize()`, closes it.
531
+ tc.result = (tc.result ?? "") + delta;
532
+ tc.isStreaming = true;
533
+ tc.streamingSource = ToolCallStreamingSource.OUTPUT;
534
+ }
535
+ // ── Post-Stream Facts ──────────────────────────────────────────────
536
+ handleApprovalProposed(scope, event) {
537
+ const now = utcTimestamp();
538
+ const existing = scope.toolCalls.get(event.callId);
539
+ if (existing) {
540
+ // Reopen (Cursor's `markWaitingApproval`): the boundary is re-proposing
541
+ // a call the stream already showed — an errored built-in the hook
542
+ // denied — so the outcome the stream wrote is not the outcome.
543
+ existing.status = ToolCallStatus.TOOL_CALL_WAITING_APPROVAL;
544
+ existing.requiresApproval = true;
545
+ existing.approvalMessage = event.message;
546
+ if (!existing.approvalRequestedAt)
547
+ existing.approvalRequestedAt = now;
548
+ existing.completedAt = "";
549
+ existing.error = "";
550
+ existing.result = "";
551
+ // The proposal's args are the authoritative proposed change when the
552
+ // harness carries them (Cursor's `applyGateInput`: the hook's captured
553
+ // input outranks what the stream carried before the first-denial cancel),
554
+ // and they re-derive the preview. Absent, the row
555
+ // keeps what it had.
556
+ if (event.args && Object.keys(event.args).length > 0) {
557
+ existing.args = event.args;
558
+ stampArgsPreview(existing, event.args);
559
+ }
560
+ if (event.contentDigest)
561
+ existing.approvalContentDigest = event.contentDigest;
562
+ stopStreaming(existing);
563
+ this._awaitingApproval = true;
564
+ this._dirty = true;
565
+ return;
566
+ }
567
+ // A call the stream never showed (native: the engine interrupted before
568
+ // the tool started). Its row lands on the text that proposed it, like
569
+ // any other row (before #1097 the seed pushed a new empty message).
570
+ const parentMsg = scope.currentAiMessage ?? this.ensureAiMessageForToolCall(scope);
571
+ const tc = create(ToolCallSchema, {
572
+ id: event.callId,
573
+ name: event.name,
574
+ status: ToolCallStatus.TOOL_CALL_WAITING_APPROVAL,
575
+ requiresApproval: true,
576
+ approvalMessage: event.message,
577
+ approvalRequestedAt: now,
578
+ startedAt: now,
579
+ });
580
+ if (event.mcpServerSlug)
581
+ tc.mcpServerSlug = event.mcpServerSlug;
582
+ tc.toolKind = classifyTool(tc.name, tc.mcpServerSlug);
583
+ if (event.provenance !== undefined) {
584
+ tc.approvalPolicySource = toProtoPolicySource(event.provenance);
585
+ tc.policyEngineVersion = POLICY_ENGINE_VERSION;
586
+ }
587
+ if (event.args && Object.keys(event.args).length > 0) {
588
+ tc.args = event.args;
589
+ stampArgsPreview(tc, event.args);
590
+ }
591
+ if (event.contentDigest)
592
+ tc.approvalContentDigest = event.contentDigest;
593
+ parentMsg.toolCalls.push(tc);
594
+ scope.toolCalls.set(event.callId, tc);
595
+ this._awaitingApproval = true;
596
+ this._dirty = true;
597
+ }
598
+ appendSystemNote(scope, text) {
599
+ scope.messages.push(create(AgentMessageSchema, {
600
+ type: MessageType.MESSAGE_SYSTEM,
601
+ content: text,
602
+ timestamp: utcTimestamp(),
603
+ }));
604
+ this._dirty = true;
605
+ }
606
+ // ── Content Helpers ───────────────────────────────────────────────
607
+ /** The AI message a run's text streams into, created on its first token; a new run closes the previous message's flag. */
608
+ ensureAiMessage(scope, runId) {
609
+ const existingByRun = scope.messagesByRun.get(runId);
610
+ if (existingByRun)
611
+ return existingByRun;
612
+ if (scope.lastRunId && scope.lastRunId !== runId && scope.currentAiMessage) {
613
+ scope.currentAiMessage.isStreaming = false;
614
+ }
615
+ const msg = create(AgentMessageSchema, {
616
+ type: MessageType.MESSAGE_AI,
617
+ content: "",
618
+ timestamp: utcTimestamp(),
619
+ isStreaming: true,
620
+ });
621
+ scope.messages.push(msg);
622
+ scope.messagesByRun.set(runId, msg);
623
+ scope.currentAiMessage = msg;
624
+ scope.lastRunId = runId;
625
+ return msg;
626
+ }
627
+ /** The message a tool row lands on when the scope has no AI message yet: the latest run's, else a new empty one. */
628
+ ensureAiMessageForToolCall(scope) {
629
+ if (scope.lastRunId) {
630
+ const existing = scope.messagesByRun.get(scope.lastRunId);
631
+ if (existing) {
632
+ scope.currentAiMessage = existing;
633
+ return existing;
634
+ }
635
+ }
636
+ const msg = create(AgentMessageSchema, {
637
+ type: MessageType.MESSAGE_AI,
638
+ content: "",
639
+ timestamp: utcTimestamp(),
640
+ isStreaming: false,
641
+ });
642
+ scope.messages.push(msg);
643
+ scope.currentAiMessage = msg;
644
+ return msg;
645
+ }
646
+ }
647
+ /** The `messagesByRun` key of a run's THINKING row — apart from the run's text, so the two never share a message. */
648
+ function thinkingKeyOf(runId) {
649
+ return `thinking:${runId}`;
650
+ }
651
+ /** Every streaming flag off in one transcript — messages and rows. */
652
+ function finalizeStreaming(transcript) {
653
+ for (const message of transcript.messages) {
654
+ message.isStreaming = false;
655
+ for (const tc of message.toolCalls)
656
+ stopStreaming(tc);
657
+ }
658
+ }
659
+ /**
660
+ * The row's `args_preview`, on EVERY row with args (since #1097):
661
+ * `message.proto` promises it sanitized, redacted, at creation, for inline
662
+ * visibility, and the one builder that keeps it small and always valid JSON
663
+ * is `buildElidedArgsPreview` over the platform's salient fields. Until then
664
+ * native stamped a whole-string-truncating preview on gated rows only and
665
+ * Cursor stamped `JSON.stringify(args)` unredacted. An empty preview (a
666
+ * cycle in the args) leaves the field unset rather than failing the row.
667
+ */
668
+ function stampArgsPreview(tc, args) {
669
+ const preview = buildElidedArgsPreview(args, SALIENT_ARG_FIELDS);
670
+ if (preview)
671
+ tc.argsPreview = preview;
672
+ }
673
+ /** A row no longer streaming: the flag off and the source cleared, so a stale OUTPUT marker never outlives the stream. */
674
+ function stopStreaming(tc) {
675
+ if (!tc.isStreaming)
676
+ return;
677
+ tc.isStreaming = false;
678
+ tc.streamingSource = ToolCallStreamingSource.UNSPECIFIED;
679
+ }
680
+ /**
681
+ * A row that has finished, however it finished — the statuses a later event
682
+ * must not move backwards (Cursor's `isTerminalToolStatus`). INTERRUPTED is
683
+ * deliberately NOT here: it is server-authored when an execution
684
+ * terminalized with the call in flight, and a recovery-replayed event must
685
+ * be able to advance the row to its true outcome (the enum's recovery
686
+ * supersede rule; `shared/tool-row.ts` explains the two sets).
687
+ */
688
+ function isSettled(status) {
689
+ return (status === ToolCallStatus.TOOL_CALL_COMPLETED ||
690
+ status === ToolCallStatus.TOOL_CALL_FAILED ||
691
+ status === ToolCallStatus.TOOL_CALL_SKIPPED);
692
+ }
693
+ //# sourceMappingURL=builder.js.map