@stigmer/runner 3.15.3-dev.20260914121148 → 3.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (592) hide show
  1. package/README.md +2 -1
  2. package/dist/.build-fingerprint +1 -1
  3. package/dist/__test-utils__/approval-contract/types.d.ts +1 -1
  4. package/dist/__test-utils__/hermetic-activity.d.ts +61 -7
  5. package/dist/__test-utils__/hermetic-activity.js +100 -9
  6. package/dist/__test-utils__/hermetic-activity.js.map +1 -1
  7. package/dist/__test-utils__/model-registry-fixture.d.ts +22 -3
  8. package/dist/__test-utils__/model-registry-fixture.js +22 -7
  9. package/dist/__test-utils__/model-registry-fixture.js.map +1 -1
  10. package/dist/activities/execute-cursor/__test-utils__/contract-subject.d.ts +2 -2
  11. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js +2 -2
  12. package/dist/activities/execute-cursor/__test-utils__/fold.d.ts +61 -0
  13. package/dist/activities/execute-cursor/__test-utils__/fold.js +94 -0
  14. package/dist/activities/execute-cursor/__test-utils__/fold.js.map +1 -0
  15. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js +1 -1
  16. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js.map +1 -1
  17. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +47 -12
  18. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +41 -10
  19. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
  20. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.d.ts +15 -6
  21. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js +17 -4
  22. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js.map +1 -1
  23. package/dist/activities/execute-cursor/adapter.d.ts +4 -4
  24. package/dist/activities/execute-cursor/adapter.js +4 -4
  25. package/dist/activities/execute-cursor/approval-policy.d.ts +10 -10
  26. package/dist/activities/execute-cursor/approval-policy.js +12 -23
  27. package/dist/activities/execute-cursor/approval-policy.js.map +1 -1
  28. package/dist/activities/execute-cursor/approval-state.d.ts +35 -1
  29. package/dist/activities/execute-cursor/approval-state.js +65 -0
  30. package/dist/activities/execute-cursor/approval-state.js.map +1 -1
  31. package/dist/activities/execute-cursor/{message-translator.d.ts → boundary-rows.d.ts} +45 -341
  32. package/dist/activities/execute-cursor/boundary-rows.js +1018 -0
  33. package/dist/activities/execute-cursor/boundary-rows.js.map +1 -0
  34. package/dist/activities/execute-cursor/cursor-capabilities.d.ts +1 -1
  35. package/dist/activities/execute-cursor/cursor-capabilities.js +1 -1
  36. package/dist/activities/execute-cursor/cursor-event-recorder.d.ts +33 -14
  37. package/dist/activities/execute-cursor/cursor-event-recorder.js +43 -21
  38. package/dist/activities/execute-cursor/cursor-event-recorder.js.map +1 -1
  39. package/dist/activities/execute-cursor/prompt-builder.d.ts +3 -3
  40. package/dist/activities/execute-cursor/prompt-builder.js +4 -4
  41. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  42. package/dist/activities/execute-cursor/service-tier.js +1 -2
  43. package/dist/activities/execute-cursor/service-tier.js.map +1 -1
  44. package/dist/activities/execute-cursor/sub-agent-steps.d.ts +79 -0
  45. package/dist/activities/execute-cursor/sub-agent-steps.js +180 -0
  46. package/dist/activities/execute-cursor/sub-agent-steps.js.map +1 -0
  47. package/dist/activities/execute-cursor/tool-result.d.ts +49 -0
  48. package/dist/activities/execute-cursor/tool-result.js +130 -0
  49. package/dist/activities/execute-cursor/tool-result.js.map +1 -0
  50. package/dist/activities/execute-cursor/translator.d.ts +178 -0
  51. package/dist/activities/execute-cursor/translator.js +485 -0
  52. package/dist/activities/execute-cursor/translator.js.map +1 -0
  53. package/dist/activities/execute-cursor/turn-boundary.d.ts +15 -5
  54. package/dist/activities/execute-cursor/turn-boundary.js +10 -14
  55. package/dist/activities/execute-cursor/turn-boundary.js.map +1 -1
  56. package/dist/activities/execute-cursor/turn-settle.d.ts +11 -7
  57. package/dist/activities/execute-cursor/turn-settle.js +47 -34
  58. package/dist/activities/execute-cursor/turn-settle.js.map +1 -1
  59. package/dist/activities/execute-cursor/turn-setup.d.ts +2 -2
  60. package/dist/activities/execute-cursor/turn-setup.js +5 -5
  61. package/dist/activities/execute-cursor/turn-setup.js.map +1 -1
  62. package/dist/activities/execute-cursor/turn-stream.d.ts +23 -14
  63. package/dist/activities/execute-cursor/turn-stream.js +41 -28
  64. package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
  65. package/dist/activities/execute-cursor/turn.d.ts +4 -4
  66. package/dist/activities/execute-cursor/turn.js +5 -5
  67. package/dist/activities/execute-cursor/usage-pricing.d.ts +2 -2
  68. package/dist/activities/execute-cursor/usage-pricing.js +2 -2
  69. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.d.ts +2 -2
  70. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js +2 -2
  71. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.d.ts +16 -11
  72. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js +22 -10
  73. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js.map +1 -1
  74. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js +1 -1
  75. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js.map +1 -1
  76. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.d.ts +2 -3
  77. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js +2 -3
  78. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js.map +1 -1
  79. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.d.ts +12 -3
  80. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js +18 -4
  81. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js.map +1 -1
  82. package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.d.ts +10 -1
  83. package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.js +24 -11
  84. package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.js.map +1 -1
  85. package/dist/activities/execute-deep-agent/adapter.d.ts +1 -1
  86. package/dist/activities/execute-deep-agent/adapter.js +1 -1
  87. package/dist/activities/execute-deep-agent/approval-file-change.d.ts +19 -19
  88. package/dist/activities/execute-deep-agent/approval-file-change.js +16 -15
  89. package/dist/activities/execute-deep-agent/approval-file-change.js.map +1 -1
  90. package/dist/activities/execute-deep-agent/deep-agent-capabilities.d.ts +2 -2
  91. package/dist/activities/execute-deep-agent/deep-agent-capabilities.js +2 -2
  92. package/dist/activities/execute-deep-agent/hitl.d.ts +2 -2
  93. package/dist/activities/execute-deep-agent/hitl.js +2 -2
  94. package/dist/activities/execute-deep-agent/inline-publisher.d.ts +13 -3
  95. package/dist/activities/execute-deep-agent/inline-publisher.js +3 -3
  96. package/dist/activities/execute-deep-agent/inline-publisher.js.map +1 -1
  97. package/dist/activities/execute-deep-agent/prompt-builder.d.ts +3 -3
  98. package/dist/activities/execute-deep-agent/prompt-builder.js +6 -7
  99. package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
  100. package/dist/activities/execute-deep-agent/streaming-side-effects.d.ts +16 -8
  101. package/dist/activities/execute-deep-agent/streaming-side-effects.js +20 -33
  102. package/dist/activities/execute-deep-agent/streaming-side-effects.js.map +1 -1
  103. package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +3 -3
  104. package/dist/activities/execute-deep-agent/subagent-transformer.js +1 -1
  105. package/dist/activities/execute-deep-agent/translator.d.ts +134 -0
  106. package/dist/activities/execute-deep-agent/translator.js +418 -0
  107. package/dist/activities/execute-deep-agent/translator.js.map +1 -0
  108. package/dist/activities/execute-deep-agent/turn-settle.d.ts +13 -7
  109. package/dist/activities/execute-deep-agent/turn-settle.js +34 -45
  110. package/dist/activities/execute-deep-agent/turn-settle.js.map +1 -1
  111. package/dist/activities/execute-deep-agent/turn-setup.d.ts +8 -8
  112. package/dist/activities/execute-deep-agent/turn-setup.js +7 -7
  113. package/dist/activities/execute-deep-agent/turn-stream.d.ts +13 -10
  114. package/dist/activities/execute-deep-agent/turn-stream.js +44 -41
  115. package/dist/activities/execute-deep-agent/turn-stream.js.map +1 -1
  116. package/dist/activities/execute-deep-agent/turn.d.ts +3 -3
  117. package/dist/activities/execute-deep-agent/turn.js +3 -3
  118. package/dist/activities/generate-session-subject.d.ts +25 -4
  119. package/dist/activities/generate-session-subject.js +17 -7
  120. package/dist/activities/generate-session-subject.js.map +1 -1
  121. package/dist/client/stigmer-client.d.ts +17 -6
  122. package/dist/client/stigmer-client.js +47 -14
  123. package/dist/client/stigmer-client.js.map +1 -1
  124. package/dist/config.d.ts +6 -3
  125. package/dist/config.js +4 -1
  126. package/dist/config.js.map +1 -1
  127. package/dist/harness/approval-decisions.d.ts +1 -1
  128. package/dist/harness/approval-decisions.js +1 -1
  129. package/dist/harness/capabilities.d.ts +21 -11
  130. package/dist/harness/capabilities.js +2 -2
  131. package/dist/harness/capture.d.ts +4 -4
  132. package/dist/harness/capture.js +4 -4
  133. package/dist/harness/persist-chokepoint.d.ts +3 -3
  134. package/dist/harness/persist-chokepoint.js +3 -3
  135. package/dist/harness/registry.d.ts +2 -2
  136. package/dist/harness/registry.js +2 -2
  137. package/dist/harness/run-turn.d.ts +6 -4
  138. package/dist/harness/run-turn.js +31 -9
  139. package/dist/harness/run-turn.js.map +1 -1
  140. package/dist/harness/stop-controller.d.ts +1 -1
  141. package/dist/harness/stop-controller.js +1 -1
  142. package/dist/harness/terminal-table.d.ts +7 -7
  143. package/dist/harness/terminal-table.js +7 -7
  144. package/dist/harness/transcript/builder.d.ts +182 -0
  145. package/dist/harness/transcript/builder.js +693 -0
  146. package/dist/harness/transcript/builder.js.map +1 -0
  147. package/dist/harness/transcript/events.d.ts +218 -0
  148. package/dist/harness/transcript/events.js +50 -0
  149. package/dist/harness/transcript/events.js.map +1 -0
  150. package/dist/harness/transcript/state.d.ts +110 -0
  151. package/dist/harness/transcript/state.js +148 -0
  152. package/dist/harness/transcript/state.js.map +1 -0
  153. package/dist/harness/turn-context.d.ts +54 -38
  154. package/dist/harness/turn-context.js +42 -43
  155. package/dist/harness/turn-context.js.map +1 -1
  156. package/dist/harness/types.d.ts +63 -22
  157. package/dist/harness/types.js +12 -11
  158. package/dist/harness/types.js.map +1 -1
  159. package/dist/harness/usage-accumulator.d.ts +2 -2
  160. package/dist/harness/usage-accumulator.js +2 -2
  161. package/dist/harness-adapters.d.ts +5 -4
  162. package/dist/harness-adapters.js +5 -4
  163. package/dist/harness-adapters.js.map +1 -1
  164. package/dist/interceptors/run-credential-activity.d.ts +28 -0
  165. package/dist/interceptors/run-credential-activity.js +56 -0
  166. package/dist/interceptors/run-credential-activity.js.map +1 -0
  167. package/dist/middleware/approval-gate.d.ts +6 -0
  168. package/dist/middleware/approval-gate.js +7 -57
  169. package/dist/middleware/approval-gate.js.map +1 -1
  170. package/dist/middleware/cost-advisory.d.ts +3 -3
  171. package/dist/middleware/cost-advisory.js +3 -3
  172. package/dist/middleware/index.d.ts +1 -1
  173. package/dist/middleware/index.js +1 -1
  174. package/dist/runner-manager.js +10 -4
  175. package/dist/runner-manager.js.map +1 -1
  176. package/dist/shared/activity-input.d.ts +9 -0
  177. package/dist/shared/activity-input.js +17 -0
  178. package/dist/shared/activity-input.js.map +1 -1
  179. package/dist/shared/approval-policy.d.ts +53 -0
  180. package/dist/shared/approval-policy.js +76 -0
  181. package/dist/shared/approval-policy.js.map +1 -1
  182. package/dist/shared/args-preview.d.ts +45 -22
  183. package/dist/shared/args-preview.js +51 -41
  184. package/dist/shared/args-preview.js.map +1 -1
  185. package/dist/shared/attachment-resolver.d.ts +4 -4
  186. package/dist/shared/attachment-resolver.js +4 -4
  187. package/dist/shared/attachment-zip.d.ts +2 -2
  188. package/dist/shared/attachment-zip.js +2 -2
  189. package/dist/shared/channel-attachment.d.ts +8 -5
  190. package/dist/shared/channel-attachment.js +10 -6
  191. package/dist/shared/channel-attachment.js.map +1 -1
  192. package/dist/shared/cost-guard.d.ts +2 -2
  193. package/dist/shared/cost-guard.js +2 -2
  194. package/dist/shared/exact-apply.d.ts +1 -1
  195. package/dist/shared/exact-apply.js +1 -1
  196. package/dist/shared/execution-context.d.ts +2 -2
  197. package/dist/shared/execution-context.js +2 -2
  198. package/dist/shared/extract-structured-output.d.ts +2 -2
  199. package/dist/shared/extract-structured-output.js +2 -2
  200. package/dist/shared/filereview/cas-touched.d.ts +2 -2
  201. package/dist/shared/filereview/cas-touched.js +2 -2
  202. package/dist/shared/filereview/progress.d.ts +13 -0
  203. package/dist/shared/filereview/progress.js +13 -0
  204. package/dist/shared/filereview/progress.js.map +1 -1
  205. package/dist/shared/heartbeat.d.ts +1 -1
  206. package/dist/shared/heartbeat.js +1 -1
  207. package/dist/shared/llm-backend.d.ts +0 -4
  208. package/dist/shared/llm-backend.js +0 -4
  209. package/dist/shared/llm-backend.js.map +1 -1
  210. package/dist/shared/memory-attachment.d.ts +16 -9
  211. package/dist/shared/memory-attachment.js +18 -10
  212. package/dist/shared/memory-attachment.js.map +1 -1
  213. package/dist/shared/model-error.d.ts +1 -2
  214. package/dist/shared/model-error.js +1 -2
  215. package/dist/shared/model-error.js.map +1 -1
  216. package/dist/shared/persist-decision.d.ts +18 -24
  217. package/dist/shared/persist-decision.js +19 -11
  218. package/dist/shared/persist-decision.js.map +1 -1
  219. package/dist/shared/prompt-sections.d.ts +4 -4
  220. package/dist/shared/prompt-sections.js +4 -4
  221. package/dist/shared/run-credential-store.d.ts +32 -0
  222. package/dist/shared/run-credential-store.js +39 -0
  223. package/dist/shared/run-credential-store.js.map +1 -0
  224. package/dist/shared/run-credential.d.ts +61 -0
  225. package/dist/shared/run-credential.js +68 -0
  226. package/dist/shared/run-credential.js.map +1 -0
  227. package/dist/shared/skill-resolver.d.ts +3 -3
  228. package/dist/shared/skill-resolver.js +3 -3
  229. package/dist/shared/status-offload.d.ts +1 -1
  230. package/dist/shared/status-offload.js +2 -2
  231. package/dist/shared/status-offload.js.map +1 -1
  232. package/dist/shared/streaming-scheduler.d.ts +2 -7
  233. package/dist/shared/streaming-scheduler.js +6 -14
  234. package/dist/shared/streaming-scheduler.js.map +1 -1
  235. package/dist/shared/subagent-rows.d.ts +2 -2
  236. package/dist/shared/subagent-rows.js +2 -2
  237. package/dist/shared/synthesized-attachment.d.ts +30 -3
  238. package/dist/shared/synthesized-attachment.js +26 -0
  239. package/dist/shared/synthesized-attachment.js.map +1 -1
  240. package/dist/shared/todos.d.ts +3 -3
  241. package/dist/shared/todos.js +3 -3
  242. package/dist/shared/tool-row.d.ts +19 -1
  243. package/dist/shared/tool-row.js +36 -2
  244. package/dist/shared/tool-row.js.map +1 -1
  245. package/dist/shared/worker-shutdown.d.ts +1 -1
  246. package/dist/shared/worker-shutdown.js +1 -1
  247. package/dist/shared/workspace/session-provision.d.ts +1 -1
  248. package/dist/shared/workspace/session-provision.js +1 -1
  249. package/dist/shared/workspace/sources/empty.d.ts +1 -1
  250. package/dist/shared/workspace/sources/empty.js +1 -2
  251. package/dist/shared/workspace/sources/empty.js.map +1 -1
  252. package/dist/shared/workspace/sources/git.js +4 -4
  253. package/dist/shared/workspace/sources/git.js.map +1 -1
  254. package/dist/shared/workspace/sources/local-path.js +6 -6
  255. package/dist/shared/workspace/sources/local-path.js.map +1 -1
  256. package/dist/shared/workspace/stigmer-link.d.ts +1 -1
  257. package/dist/shared/workspace/stigmer-link.js +1 -1
  258. package/dist/shared/workspace/types.d.ts +2 -5
  259. package/dist/shared/workspace/types.js +0 -6
  260. package/dist/shared/workspace/types.js.map +1 -1
  261. package/dist/shared/workspace/writeback-coordinator.d.ts +17 -4
  262. package/dist/shared/workspace/writeback-coordinator.js +7 -9
  263. package/dist/shared/workspace/writeback-coordinator.js.map +1 -1
  264. package/dist/worker.js +10 -3
  265. package/dist/worker.js.map +1 -1
  266. package/dist/workflow-source.d.ts +10 -0
  267. package/dist/workflow-source.js +12 -0
  268. package/dist/workflow-source.js.map +1 -1
  269. package/dist/workflows/execute-from-execution.d.ts +15 -0
  270. package/dist/workflows/execute-from-execution.js +11 -0
  271. package/dist/workflows/execute-from-execution.js.map +1 -1
  272. package/dist/workflows/index.d.ts +5 -3
  273. package/dist/workflows/index.js +5 -3
  274. package/dist/workflows/index.js.map +1 -1
  275. package/dist/workflows/interceptors/run-credential.d.ts +34 -0
  276. package/dist/workflows/interceptors/run-credential.js +71 -0
  277. package/dist/workflows/interceptors/run-credential.js.map +1 -0
  278. package/package.json +4 -4
  279. package/src/__test-utils__/__tests__/execution-record-barrier.test.ts +70 -0
  280. package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +35 -1
  281. package/src/__test-utils__/approval-contract/contract.ts +1 -1
  282. package/src/__test-utils__/approval-contract/types.ts +1 -1
  283. package/src/__test-utils__/harness-boot-order-child.ts +1 -1
  284. package/src/__test-utils__/harness-contract/contract.ts +8 -8
  285. package/src/__test-utils__/harness-contract/recording-sink.ts +11 -1
  286. package/src/__test-utils__/harness-contract/runtime-contract.ts +52 -16
  287. package/src/__test-utils__/harness-contract/scripted-adapter.ts +47 -43
  288. package/src/__test-utils__/hermetic-activity.ts +113 -9
  289. package/src/__test-utils__/model-registry-fixture.ts +31 -7
  290. package/src/__test-utils__/module-specifiers.ts +32 -3
  291. package/src/__tests__/harness-boot-order.test.ts +1 -1
  292. package/src/__tests__/harness-contract.test.ts +1 -1
  293. package/src/__tests__/run-credential-e2e.test.ts +233 -0
  294. package/src/__tests__/run-credential-registration.test.ts +80 -0
  295. package/src/__tests__/runner-manager.test.ts +1 -1
  296. package/src/activities/__tests__/generate-session-subject-wire.test.ts +119 -0
  297. package/src/activities/execute-cursor/__test-utils__/__tests__/scripted-double.test.ts +1 -1
  298. package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +2 -2
  299. package/src/activities/execute-cursor/__test-utils__/fold.ts +116 -0
  300. package/src/activities/execute-cursor/__test-utils__/gateway-substrate.ts +1 -1
  301. package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +67 -17
  302. package/src/activities/execute-cursor/__test-utils__/scripted-agent.ts +19 -5
  303. package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +2 -1
  304. package/src/activities/execute-cursor/__tests__/approval-state.test.ts +14 -21
  305. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +3 -3
  306. package/src/activities/execute-cursor/__tests__/coarse-fingerprint.test.ts +2 -1
  307. package/src/activities/execute-cursor/__tests__/cursor-event-recorder.test.ts +142 -0
  308. package/src/activities/execute-cursor/__tests__/cursor-fetch-interceptor-bypass.test.ts +19 -8
  309. package/src/activities/execute-cursor/__tests__/cursor-sdk-auth-smoke.test.ts +10 -8
  310. package/src/activities/execute-cursor/__tests__/cursor-transcript-live.test.ts +298 -0
  311. package/src/activities/execute-cursor/__tests__/deny-gate-exact-apply.test.ts +4 -2
  312. package/src/activities/execute-cursor/__tests__/fetch-interceptor.test.ts +1 -1
  313. package/src/activities/execute-cursor/__tests__/hermetic/deny-and-retry.test.ts +1 -1
  314. package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +1 -1
  315. package/src/activities/execute-cursor/__tests__/hermetic/goldens/mcp-tool-call.status.json +71 -0
  316. package/src/activities/execute-cursor/__tests__/hermetic/goldens/sdk-task-note.status.json +73 -0
  317. package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.error-delta.status.json +78 -0
  318. package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.output-first.status.json +72 -0
  319. package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.status.json +72 -0
  320. package/src/activities/execute-cursor/__tests__/hermetic/goldens/sub-agent-delegation.status.json +109 -0
  321. package/src/activities/execute-cursor/__tests__/hermetic/goldens/thinking-turn.status.json +78 -0
  322. package/src/activities/execute-cursor/__tests__/hermetic/goldens/todo-write.status.json +119 -0
  323. package/src/activities/execute-cursor/__tests__/hermetic/goldens/tool-error.status.json +68 -0
  324. package/src/activities/execute-cursor/__tests__/hermetic/goldens/tool-only-step.status.json +67 -0
  325. package/src/activities/execute-cursor/__tests__/hermetic/goldens/unattributed-hook-block.status.json +1 -1
  326. package/src/activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts +7 -7
  327. package/src/activities/execute-cursor/__tests__/hermetic/mcp-tool-call.test.ts +146 -0
  328. package/src/activities/execute-cursor/__tests__/hermetic/pause-vs-shutdown.test.ts +5 -5
  329. package/src/activities/execute-cursor/__tests__/hermetic/plain-turn.test.ts +2 -1
  330. package/src/activities/execute-cursor/__tests__/hermetic/run-wait-arms.test.ts +2 -1
  331. package/src/activities/execute-cursor/__tests__/hermetic/sdk-task-note.test.ts +122 -0
  332. package/src/activities/execute-cursor/__tests__/hermetic/shell-output-delta.test.ts +276 -0
  333. package/src/activities/execute-cursor/__tests__/hermetic/stream-self-stop-arms.test.ts +8 -8
  334. package/src/activities/execute-cursor/__tests__/hermetic/sub-agent-delegation.test.ts +196 -0
  335. package/src/activities/execute-cursor/__tests__/hermetic/thinking-turn.test.ts +145 -0
  336. package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +1 -1
  337. package/src/activities/execute-cursor/__tests__/hermetic/todo-write.test.ts +165 -0
  338. package/src/activities/execute-cursor/__tests__/hermetic/tool-call.test.ts +3 -3
  339. package/src/activities/execute-cursor/__tests__/hermetic/tool-error.test.ts +138 -0
  340. package/src/activities/execute-cursor/__tests__/hermetic/tool-only-step.test.ts +130 -0
  341. package/src/activities/execute-cursor/__tests__/hermetic/unattributed-hook-block.test.ts +13 -1
  342. package/src/activities/execute-cursor/__tests__/hermetic/workspace-lock-timeout.test.ts +2 -2
  343. package/src/activities/execute-cursor/__tests__/hitl-ledger.test.ts +43 -60
  344. package/src/activities/execute-cursor/__tests__/hitl-resume-history.test.ts +23 -28
  345. package/src/activities/execute-cursor/__tests__/hook-script.test.ts +2 -1
  346. package/src/activities/execute-cursor/__tests__/http2-interceptor.test.ts +1 -1
  347. package/src/activities/execute-cursor/__tests__/prompt-goldens.test.ts +5 -5
  348. package/src/activities/execute-cursor/__tests__/same-identity-reproposal.test.ts +11 -13
  349. package/src/activities/execute-cursor/__tests__/sequential-gate-resume.test.ts +8 -11
  350. package/src/activities/execute-cursor/__tests__/tool-result-image.test.ts +8 -22
  351. package/src/activities/execute-cursor/__tests__/translator.test.ts +594 -0
  352. package/src/activities/execute-cursor/__tests__/turn-boundary.test.ts +8 -5
  353. package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +87 -63
  354. package/src/activities/execute-cursor/adapter.ts +4 -4
  355. package/src/activities/execute-cursor/approval-policy.ts +12 -24
  356. package/src/activities/execute-cursor/approval-state.ts +66 -1
  357. package/src/activities/execute-cursor/boundary-rows.ts +1132 -0
  358. package/src/activities/execute-cursor/cursor-capabilities.ts +1 -1
  359. package/src/activities/execute-cursor/cursor-event-recorder.ts +57 -28
  360. package/src/activities/execute-cursor/fetch-interceptor.ts +1 -1
  361. package/src/activities/execute-cursor/http2-interceptor.ts +1 -1
  362. package/src/activities/execute-cursor/prompt-builder.ts +6 -6
  363. package/src/activities/execute-cursor/service-tier.ts +1 -2
  364. package/src/activities/execute-cursor/sub-agent-steps.ts +188 -0
  365. package/src/activities/execute-cursor/tool-result.ts +128 -0
  366. package/src/activities/execute-cursor/translator.ts +541 -0
  367. package/src/activities/execute-cursor/turn-boundary.ts +21 -14
  368. package/src/activities/execute-cursor/turn-settle.ts +46 -34
  369. package/src/activities/execute-cursor/turn-setup.ts +5 -5
  370. package/src/activities/execute-cursor/turn-stream.ts +49 -46
  371. package/src/activities/execute-cursor/turn.ts +5 -5
  372. package/src/activities/execute-cursor/usage-pricing.ts +2 -2
  373. package/src/activities/execute-deep-agent/__test-utils__/contract-subject.ts +2 -2
  374. package/src/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.ts +23 -11
  375. package/src/activities/execute-deep-agent/__test-utils__/hitl-script.ts +1 -1
  376. package/src/activities/execute-deep-agent/__test-utils__/scripted-model-module.ts +2 -3
  377. package/src/activities/execute-deep-agent/__test-utils__/scripted-model.ts +25 -4
  378. package/src/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.ts +25 -11
  379. package/src/activities/execute-deep-agent/__tests__/adapter-graph-is-sdk-free.test.ts +1 -1
  380. package/src/activities/execute-deep-agent/__tests__/adapter-is-temporal-free.test.ts +1 -1
  381. package/src/activities/execute-deep-agent/__tests__/approval-file-change.test.ts +6 -17
  382. package/src/activities/execute-deep-agent/__tests__/hermetic/file-review-capture.test.ts +25 -8
  383. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn1.status.json +2 -7
  384. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn2.status.json +4 -14
  385. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve.turn2.status.json +1 -5
  386. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/file-review-capture.status.json +4 -7
  387. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/gate.turn1.status.json +1 -5
  388. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn1.status.json +2 -9
  389. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn2.status.json +2 -9
  390. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.after-tool.status.json +1 -4
  391. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.mid-tool.status.json +1 -4
  392. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/platform-stop.status.json +1 -4
  393. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/recursion-limit.persisted.status.json +109 -76
  394. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/reject.turn2.status.json +1 -5
  395. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn2.status.json +2 -10
  396. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn3.status.json +2 -10
  397. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/skip.turn2.status.json +1 -5
  398. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sub-agent-delegation.status.json +3 -6
  399. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/tool-call.status.json +1 -4
  400. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/worker-shutdown.status.json +1 -4
  401. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/write-todos.status.json +92 -0
  402. package/src/activities/execute-deep-agent/__tests__/hermetic/harness-contract.test.ts +3 -3
  403. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-approve-all-lease.test.ts +9 -5
  404. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-round-trips.test.ts +3 -3
  405. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-sequential-gates.test.ts +3 -3
  406. package/src/activities/execute-deep-agent/__tests__/hermetic/inline-artifact-across-gate.test.ts +7 -6
  407. package/src/activities/execute-deep-agent/__tests__/hermetic/pause-vs-shutdown.test.ts +10 -11
  408. package/src/activities/execute-deep-agent/__tests__/hermetic/plain-turn.test.ts +4 -4
  409. package/src/activities/execute-deep-agent/__tests__/hermetic/platform-stop.test.ts +9 -8
  410. package/src/activities/execute-deep-agent/__tests__/hermetic/recursion-limit.test.ts +21 -13
  411. package/src/activities/execute-deep-agent/__tests__/hermetic/resolution-error.test.ts +2 -2
  412. package/src/activities/execute-deep-agent/__tests__/hermetic/structured-output.test.ts +7 -7
  413. package/src/activities/execute-deep-agent/__tests__/hermetic/sub-agent-delegation.test.ts +28 -12
  414. package/src/activities/execute-deep-agent/__tests__/hermetic/tool-call.test.ts +21 -21
  415. package/src/activities/execute-deep-agent/__tests__/hermetic/workspace-lock-timeout.test.ts +5 -5
  416. package/src/activities/execute-deep-agent/__tests__/hermetic/write-todos.test.ts +160 -0
  417. package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +35 -30
  418. package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +3 -4
  419. package/src/activities/execute-deep-agent/__tests__/prompt-goldens.test.ts +12 -10
  420. package/src/activities/execute-deep-agent/__tests__/scripted-model.test.ts +13 -3
  421. package/src/activities/execute-deep-agent/__tests__/streaming-side-effects.test.ts +26 -18
  422. package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +1 -1
  423. package/src/activities/execute-deep-agent/__tests__/{subagent-tracker.test.ts → translator-subagents.test.ts} +76 -57
  424. package/src/activities/execute-deep-agent/__tests__/{v3-status-builder.test.ts → translator-through-builder.test.ts} +213 -299
  425. package/src/activities/execute-deep-agent/__tests__/translator.test.ts +505 -0
  426. package/src/activities/execute-deep-agent/__tests__/turn-stream.test.ts +11 -29
  427. package/src/activities/execute-deep-agent/adapter.ts +1 -1
  428. package/src/activities/execute-deep-agent/approval-file-change.ts +20 -22
  429. package/src/activities/execute-deep-agent/deep-agent-capabilities.ts +2 -2
  430. package/src/activities/execute-deep-agent/hitl.ts +2 -2
  431. package/src/activities/execute-deep-agent/inline-publisher.ts +16 -5
  432. package/src/activities/execute-deep-agent/prompt-builder.ts +6 -7
  433. package/src/activities/execute-deep-agent/streaming-side-effects.ts +22 -31
  434. package/src/activities/execute-deep-agent/subagent-transformer.ts +3 -3
  435. package/src/activities/execute-deep-agent/translator.ts +463 -0
  436. package/src/activities/execute-deep-agent/turn-settle.ts +35 -43
  437. package/src/activities/execute-deep-agent/turn-setup.ts +8 -8
  438. package/src/activities/execute-deep-agent/turn-stream.ts +53 -51
  439. package/src/activities/execute-deep-agent/turn.ts +3 -3
  440. package/src/activities/generate-session-subject.ts +29 -4
  441. package/src/client/__tests__/stigmer-client.test.ts +92 -0
  442. package/src/client/stigmer-client.ts +48 -14
  443. package/src/config.ts +6 -3
  444. package/src/harness/README.md +335 -0
  445. package/src/harness/__tests__/approval-decisions.test.ts +2 -2
  446. package/src/harness/__tests__/capture.test.ts +3 -3
  447. package/src/harness/__tests__/import-direction.test.ts +3 -2
  448. package/src/harness/__tests__/mount-skills.test.ts +4 -1
  449. package/src/harness/__tests__/readme-index.test.ts +339 -0
  450. package/src/harness/__tests__/run-turn.test.ts +131 -6
  451. package/src/harness/__tests__/transcript-is-engine-free.test.ts +83 -0
  452. package/src/harness/__tests__/transcript-writers.test.ts +191 -0
  453. package/src/harness/__tests__/turn-attachments-vision.test.ts +5 -2
  454. package/src/harness/__tests__/turn-context.test.ts +5 -5
  455. package/src/harness/approval-decisions.ts +1 -1
  456. package/src/harness/capabilities.ts +21 -11
  457. package/src/harness/capture.ts +4 -4
  458. package/src/harness/persist-chokepoint.ts +3 -3
  459. package/src/harness/registry.ts +2 -2
  460. package/src/harness/run-turn.ts +33 -9
  461. package/src/harness/stop-controller.ts +1 -1
  462. package/src/harness/terminal-table.ts +7 -7
  463. package/src/harness/transcript/__tests__/builder.test.ts +975 -0
  464. package/src/harness/transcript/__tests__/state.test.ts +143 -0
  465. package/src/harness/transcript/builder.ts +755 -0
  466. package/src/harness/transcript/events.ts +262 -0
  467. package/src/harness/transcript/state.ts +167 -0
  468. package/src/harness/turn-context.ts +61 -46
  469. package/src/harness/types.ts +64 -22
  470. package/src/harness/usage-accumulator.ts +2 -2
  471. package/src/harness-adapters.ts +5 -4
  472. package/src/interceptors/__tests__/run-credential-activity.test.ts +133 -0
  473. package/src/interceptors/run-credential-activity.ts +67 -0
  474. package/src/middleware/__tests__/cost-advisory.test.ts +2 -2
  475. package/src/middleware/approval-gate.ts +7 -74
  476. package/src/middleware/cost-advisory.ts +3 -3
  477. package/src/middleware/index.ts +1 -1
  478. package/src/runner-manager.ts +14 -4
  479. package/src/shared/__tests__/approval-policy.test.ts +45 -0
  480. package/src/shared/__tests__/args-preview.test.ts +40 -20
  481. package/src/shared/__tests__/attachment-naming.test.ts +1 -1
  482. package/src/shared/__tests__/attachment-resolver.test.ts +5 -5
  483. package/src/shared/__tests__/attachment-zip.test.ts +1 -1
  484. package/src/shared/__tests__/blueprint-resolver.test.ts +1 -1
  485. package/src/shared/__tests__/channel-attachment.test.ts +12 -0
  486. package/src/shared/__tests__/cost-guard.test.ts +1 -1
  487. package/src/shared/__tests__/exact-apply.test.ts +2 -1
  488. package/src/shared/__tests__/memory-attachment.test.ts +17 -0
  489. package/src/shared/__tests__/persist-decision.test.ts +19 -33
  490. package/src/shared/__tests__/prompt-sections.test.ts +1 -1
  491. package/src/shared/__tests__/run-credential.test.ts +111 -0
  492. package/src/shared/__tests__/stamp-flowed-rows.test.ts +1 -1
  493. package/src/shared/__tests__/status-offload.test.ts +1 -1
  494. package/src/shared/__tests__/streaming-scheduler.test.ts +8 -9
  495. package/src/shared/__tests__/todos.test.ts +1 -1
  496. package/src/shared/__tests__/tool-row.test.ts +1 -1
  497. package/src/shared/activity-input.ts +21 -0
  498. package/src/shared/approval-policy.ts +95 -0
  499. package/src/shared/args-preview.ts +51 -42
  500. package/src/shared/attachment-resolver.ts +4 -4
  501. package/src/shared/attachment-zip.ts +2 -2
  502. package/src/shared/channel-attachment.ts +14 -6
  503. package/src/shared/cost-guard.ts +2 -2
  504. package/src/shared/exact-apply.ts +1 -1
  505. package/src/shared/execution-context.ts +2 -2
  506. package/src/shared/extract-structured-output.ts +2 -2
  507. package/src/shared/filereview/__tests__/capture.test.ts +9 -5
  508. package/src/shared/filereview/__tests__/git-substrate.test.ts +4 -1
  509. package/src/shared/filereview/__tests__/proxy-reconcile.test.ts +3 -3
  510. package/src/shared/filereview/cas-touched.ts +2 -2
  511. package/src/shared/filereview/progress.ts +13 -0
  512. package/src/shared/heartbeat.ts +1 -1
  513. package/src/shared/llm-backend.ts +0 -4
  514. package/src/shared/memory-attachment.ts +22 -10
  515. package/src/shared/model-error.ts +1 -2
  516. package/src/shared/persist-decision.ts +19 -28
  517. package/src/shared/prompt-sections.ts +4 -4
  518. package/src/shared/run-credential-store.ts +45 -0
  519. package/src/shared/run-credential.ts +70 -0
  520. package/src/shared/skill-resolver.ts +3 -3
  521. package/src/shared/status-offload.ts +2 -2
  522. package/src/shared/streaming-scheduler.ts +8 -13
  523. package/src/shared/subagent-rows.ts +2 -2
  524. package/src/shared/synthesized-attachment.ts +38 -3
  525. package/src/shared/todos.ts +3 -3
  526. package/src/shared/tool-row.ts +38 -2
  527. package/src/shared/worker-shutdown.ts +1 -1
  528. package/src/shared/workspace/__tests__/git-source.test.ts +3 -3
  529. package/src/shared/workspace/__tests__/provisioner.test.ts +5 -5
  530. package/src/shared/workspace/__tests__/session-provision.test.ts +2 -2
  531. package/src/shared/workspace/__tests__/writeback-coordinator.integration.test.ts +8 -9
  532. package/src/shared/workspace/__tests__/writeback-coordinator.test.ts +25 -25
  533. package/src/shared/workspace/provisioner.ts +1 -1
  534. package/src/shared/workspace/session-provision.ts +1 -1
  535. package/src/shared/workspace/sources/empty.ts +2 -2
  536. package/src/shared/workspace/sources/git.ts +3 -4
  537. package/src/shared/workspace/sources/local-path.ts +5 -6
  538. package/src/shared/workspace/stigmer-link.ts +1 -1
  539. package/src/shared/workspace/types.ts +2 -5
  540. package/src/shared/workspace/writeback-coordinator.ts +23 -12
  541. package/src/worker.ts +15 -3
  542. package/src/workflow-source.ts +15 -0
  543. package/src/workflows/__tests__/run-credential-interceptor.test.ts +178 -0
  544. package/src/workflows/execute-from-execution.ts +17 -0
  545. package/src/workflows/index.ts +5 -3
  546. package/src/workflows/interceptors/run-credential.ts +101 -0
  547. package/dist/activities/execute-cursor/delta-enricher.d.ts +0 -87
  548. package/dist/activities/execute-cursor/delta-enricher.js +0 -265
  549. package/dist/activities/execute-cursor/delta-enricher.js.map +0 -1
  550. package/dist/activities/execute-cursor/message-translator.js +0 -2040
  551. package/dist/activities/execute-cursor/message-translator.js.map +0 -1
  552. package/dist/activities/execute-cursor/todo-tracker.d.ts +0 -40
  553. package/dist/activities/execute-cursor/todo-tracker.js +0 -80
  554. package/dist/activities/execute-cursor/todo-tracker.js.map +0 -1
  555. package/dist/activities/execute-deep-agent/execution-state.d.ts +0 -54
  556. package/dist/activities/execute-deep-agent/execution-state.js +0 -68
  557. package/dist/activities/execute-deep-agent/execution-state.js.map +0 -1
  558. package/dist/activities/execute-deep-agent/status-builder-shared.d.ts +0 -65
  559. package/dist/activities/execute-deep-agent/status-builder-shared.js +0 -90
  560. package/dist/activities/execute-deep-agent/status-builder-shared.js.map +0 -1
  561. package/dist/activities/execute-deep-agent/subagent-tracker.d.ts +0 -113
  562. package/dist/activities/execute-deep-agent/subagent-tracker.js +0 -400
  563. package/dist/activities/execute-deep-agent/subagent-tracker.js.map +0 -1
  564. package/dist/activities/execute-deep-agent/v3-events.d.ts +0 -102
  565. package/dist/activities/execute-deep-agent/v3-events.js +0 -35
  566. package/dist/activities/execute-deep-agent/v3-events.js.map +0 -1
  567. package/dist/activities/execute-deep-agent/v3-protocol-normalizer.d.ts +0 -15
  568. package/dist/activities/execute-deep-agent/v3-protocol-normalizer.js +0 -235
  569. package/dist/activities/execute-deep-agent/v3-protocol-normalizer.js.map +0 -1
  570. package/dist/activities/execute-deep-agent/v3-status-builder.d.ts +0 -111
  571. package/dist/activities/execute-deep-agent/v3-status-builder.js +0 -457
  572. package/dist/activities/execute-deep-agent/v3-status-builder.js.map +0 -1
  573. package/dist/shared/execution-status-writer.d.ts +0 -31
  574. package/dist/shared/execution-status-writer.js +0 -43
  575. package/dist/shared/execution-status-writer.js.map +0 -1
  576. package/src/activities/execute-cursor/__tests__/delta-enricher.test.ts +0 -310
  577. package/src/activities/execute-cursor/__tests__/message-translator.test.ts +0 -1033
  578. package/src/activities/execute-cursor/__tests__/todo-tracker.test.ts +0 -498
  579. package/src/activities/execute-cursor/delta-enricher.ts +0 -307
  580. package/src/activities/execute-cursor/message-translator.ts +0 -2319
  581. package/src/activities/execute-cursor/todo-tracker.ts +0 -91
  582. package/src/activities/execute-deep-agent/__tests__/execution-state-extended.test.ts +0 -148
  583. package/src/activities/execute-deep-agent/__tests__/execution-state.test.ts +0 -154
  584. package/src/activities/execute-deep-agent/__tests__/status-builder-shared.test.ts +0 -47
  585. package/src/activities/execute-deep-agent/__tests__/v3-protocol-normalizer.test.ts +0 -324
  586. package/src/activities/execute-deep-agent/execution-state.ts +0 -78
  587. package/src/activities/execute-deep-agent/status-builder-shared.ts +0 -142
  588. package/src/activities/execute-deep-agent/subagent-tracker.ts +0 -479
  589. package/src/activities/execute-deep-agent/v3-events.ts +0 -153
  590. package/src/activities/execute-deep-agent/v3-protocol-normalizer.ts +0 -264
  591. package/src/activities/execute-deep-agent/v3-status-builder.ts +0 -565
  592. package/src/shared/execution-status-writer.ts +0 -56
@@ -18,7 +18,7 @@
18
18
  * - File review under the `cursor` harness id, with the two files the gate
19
19
  * writes into the repo excluded from the mid-run progress diff
20
20
  * ({@link CURSOR_RUNNER_OWNED_PATHS}). The capture itself is the runtime's
21
- * (`harness/capture.ts`, S3 M4); this adapter contributes only the hook
21
+ * (`harness/capture.ts`, since #1096); this adapter contributes only the hook
22
22
  * sidecar it binds as the runtime's CAS observations (`turn-setup.ts`).
23
23
  */
24
24
 
@@ -1,57 +1,91 @@
1
1
  /**
2
- * Cursor SDK event recorder for capturing raw SDKMessage events.
2
+ * The raw recording of the Cursor translator's input — both SDK channels, in
3
+ * arrival order — for checking the translator against what the real SDK sends.
3
4
  *
4
- * Activated by the CURSOR_EVENT_RECORD_DIR environment variable. When set,
5
- * the Cursor streaming loop records every SDKMessage and flushes them
6
- * atomically to a JSONL file after the stream completes.
5
+ * Off unless `CURSOR_EVENT_RECORD_DIR` is set: `turn-settle.ts` reads the env
6
+ * once per turn and hands the directory in, so this module touches no process
7
+ * state and its tests need no env. When off, {@link createCursorEventRecorder}
8
+ * returns undefined and the loop's `recorder?.record(...)` costs nothing.
7
9
  *
8
- * This is development infrastructure for validating the agent_id-based
9
- * sub-agent routing hypothesis. The captured events reveal whether
10
- * sub-agent events carry distinct agent_id values and whether they
11
- * flow through the parent's run.stream() at all.
10
+ * Two channels, one sequence. The Cursor SDK hands the runner a turn on two
11
+ * channels: the discrete `run.stream()` `SDKMessage`s (message boundaries, tool
12
+ * calls, the result) and the fine-grained `onDelta` `InteractionUpdate`s (text
13
+ * and thinking tokens, live shell output, tool-call completion instants,
14
+ * usage). The translator (`translator.ts`) reads both, and the questions a
15
+ * recording exists to answer — what shape `shell-output-delta` carries, whether
16
+ * `tool-call-completed` arrives before or after the stream's own completed
17
+ * `tool_call` — are questions about the ORDER across channels. So the recorder
18
+ * owns one monotonic `seq` and stamps every line with its `channel`; a reader
19
+ * sorts nothing, it reads the file top to bottom. Until #1097's live-run gate
20
+ * this module recorded the stream channel alone, under the loop's own
21
+ * event counter, which could not place a delta relative to a stream event.
12
22
  *
13
- * Mirrors the native harness's v3-event-recorder.ts / V3_EVENT_RECORD_DIR.
23
+ * Output: `<dir>/<executionId>.cursor-events.jsonl`, one JSON object per line,
24
+ * flushed once after the stream completes (`turn-settle.ts`). Payloads pass
25
+ * through {@link safeClone} so a cyclic event cannot fail the flush. The native
26
+ * harness's `v3-event-recorder.ts` is the same idea for its one channel.
14
27
  */
15
28
 
16
29
  import { writeFile, mkdir } from "node:fs/promises";
17
30
  import { join } from "node:path";
18
- import type { SDKMessage } from "@cursor/sdk";
31
+ import type { InteractionUpdate, SDKMessage } from "@cursor/sdk";
32
+
33
+ /** Which of the SDK's two channels a recorded line came from. */
34
+ export type CursorRecordedChannel = "stream" | "delta";
19
35
 
20
36
  export interface CursorEventRecorder {
21
- record(event: SDKMessage, seq: number): void;
37
+ /** A discrete `run.stream()` event, sequenced with the deltas around it. */
38
+ record(event: SDKMessage): void;
39
+ /** An `onDelta` update, sequenced with the stream events around it. */
40
+ recordDelta(update: InteractionUpdate): void;
41
+ /** Write every recorded line, once. A no-op when nothing was recorded. */
22
42
  flush(): Promise<void>;
23
43
  }
24
44
 
25
45
  /**
26
- * Create a recorder if CURSOR_EVENT_RECORD_DIR is set, otherwise undefined.
27
- * The caller does `recorder?.record(event, seq)` — zero overhead when off.
46
+ * Create a recorder for `recordDir`, or undefined when there is none (the
47
+ * env var unset or empty) — the caller does `recorder?.record(event)`.
28
48
  */
29
49
  export function createCursorEventRecorder(
30
50
  executionId: string,
51
+ recordDir: string | undefined,
31
52
  ): CursorEventRecorder | undefined {
32
- const recordDir = process.env.CURSOR_EVENT_RECORD_DIR;
33
53
  if (!recordDir) return undefined;
34
54
  return new FileCursorEventRecorder(executionId, recordDir);
35
55
  }
36
56
 
37
57
  class FileCursorEventRecorder implements CursorEventRecorder {
38
58
  private readonly lines: string[] = [];
59
+ /** The one arrival counter both channels share (the header's reason). */
60
+ private seq = 0;
39
61
 
40
62
  constructor(
41
63
  private readonly executionId: string,
42
64
  private readonly outputDir: string,
43
65
  ) {}
44
66
 
45
- record(event: SDKMessage, seq: number): void {
46
- const entry = {
47
- seq,
48
- capturedAt: new Date().toISOString(),
49
- type: event.type,
67
+ record(event: SDKMessage): void {
68
+ this.append("stream", event.type, {
50
69
  agent_id: event.agent_id,
51
70
  run_id: event.run_id,
52
71
  event: safeClone(event),
53
- };
54
- this.lines.push(JSON.stringify(entry));
72
+ });
73
+ }
74
+
75
+ recordDelta(update: InteractionUpdate): void {
76
+ this.append("delta", update.type, { update: safeClone(update) });
77
+ }
78
+
79
+ private append(channel: CursorRecordedChannel, type: string, payload: Record<string, unknown>): void {
80
+ this.lines.push(
81
+ JSON.stringify({
82
+ seq: this.seq++,
83
+ capturedAt: new Date().toISOString(),
84
+ channel,
85
+ type,
86
+ ...payload,
87
+ }),
88
+ );
55
89
  }
56
90
 
57
91
  async flush(): Promise<void> {
@@ -59,15 +93,10 @@ class FileCursorEventRecorder implements CursorEventRecorder {
59
93
 
60
94
  await mkdir(this.outputDir, { recursive: true });
61
95
 
62
- const filePath = join(
63
- this.outputDir,
64
- `${this.executionId}.cursor-events.jsonl`,
65
- );
96
+ const filePath = join(this.outputDir, `${this.executionId}.cursor-events.jsonl`);
66
97
 
67
98
  await writeFile(filePath, this.lines.join("\n") + "\n");
68
- console.log(
69
- `CursorEventRecorder: flushed ${this.lines.length} events to ${filePath}`,
70
- );
99
+ console.log(`CursorEventRecorder: flushed ${this.lines.length} lines to ${filePath}`);
71
100
  }
72
101
  }
73
102
 
@@ -65,7 +65,7 @@ interface ProxyConfig {
65
65
  * manager's token coordinator), so a rotation reaches the next request
66
66
  * without a call into this module. Which credential it is differs per
67
67
  * root — the static root's control-plane token, the manager's minted
68
- * runner token (Q-S2-7) — and this module never knows which.
68
+ * runner token — and this module never knows which.
69
69
  */
70
70
  proxyTokenRef: { readonly current: string | null };
71
71
  executionId?: string;
@@ -64,7 +64,7 @@ interface Http2InterceptorConfig {
64
64
  * installed this interceptor owns the ref and rotates it in place, so a
65
65
  * rotation reaches the next `request()` on an already-open session without
66
66
  * a call into this module (see fetch-interceptor.ts for the two roots'
67
- * bindings, Q-S2-7).
67
+ * bindings).
68
68
  */
69
69
  proxyTokenRef: { readonly current: string | null };
70
70
  }
@@ -6,7 +6,7 @@
6
6
  * user message and persist in the agent's own conversation store; a resumed
7
7
  * agent receives only what is per-turn).
8
8
  *
9
- * What is this harness's and what is shared (S3 M5, Q-S3-10 / Q-M5-2):
9
+ * What is this harness's and what is shared (since #1096):
10
10
  * - Shared through `shared/prompt-sections.ts`: WHICH standing sections
11
11
  * render and in WHAT order (`standingContextSections`) and the input-files
12
12
  * bullet and disclosure lines (`inputFileLines`). Their WORDS come from
@@ -70,7 +70,7 @@ const RUNNER_PATH_MARKERS = [
70
70
  ] as const;
71
71
 
72
72
  // The prompt renders the attachment resolver's own result type — a local
73
- // structural twin (`AttachmentPromptEntry`) lived here until S3 M5 and the
73
+ // structural twin (`AttachmentPromptEntry`) lived here until #1096 and the
74
74
  // projection into it was the one reason `turn-setup.ts` had a
75
75
  // `prepareAttachmentPrompt` step; the twin dropped the size, so this
76
76
  // harness's input-files line never carried it. One type, one truth: the
@@ -315,7 +315,7 @@ export function buildReinvocationPrompt(
315
315
  } else if (action === ApprovalAction.REJECT) {
316
316
  // A REJECT denies the tool and the run continues (stigmer#197); the
317
317
  // runtime settles its row SKIPPED. Told apart from a SKIP in the prose
318
- // so the model reads a refusal, not an omission (S3 M1, Q-S3-2).
318
+ // so the model reads a refusal, not an omission (since #1096).
319
319
  rejected.push(describeApproval(pa));
320
320
  }
321
321
  }
@@ -566,8 +566,8 @@ export function formatWorkspaceContext(dirs: string[]): string {
566
566
  /**
567
567
  * The `<input_files>` section: this harness's intro around the shared lines
568
568
  * (`prompt-sections.ts` `inputFileLines` says what each bullet and disclosure
569
- * carries and why). The size on each bullet is new to this harness at S3 M5
570
- * (Q-M5-3): the twin this builder rendered from had dropped it.
569
+ * carries and why). The size on each bullet is new to this harness in #1096:
570
+ * the twin this builder rendered from had dropped it.
571
571
  */
572
572
  export function formatInputFiles(
573
573
  attachments: readonly ResolvedAttachment[],
@@ -755,7 +755,7 @@ export function buildToolApprovalRuleFile(): string {
755
755
  // ---------------------------------------------------------------------------
756
756
  // Prompt selection — which of the four shapes a turn sends, from how the
757
757
  // agent resolved and whether the turn carries adjudicated approvals. Moved
758
- // from `index.ts` at S2 M3b, body unchanged; `__tests__/build-prompt.test.ts`
758
+ // from `index.ts` in #1070, body unchanged; `__tests__/build-prompt.test.ts`
759
759
  // pins every branch.
760
760
  // ---------------------------------------------------------------------------
761
761
 
@@ -53,8 +53,7 @@ const AUTO_MODEL_IDS = new Set(["default", "auto"]);
53
53
  * the served variant deterministic while leaving effort knobs on their
54
54
  * catalog defaults. `fast` changes the per-token price; `thinking` is
55
55
  * price-neutral but changes token consumption and must never follow the
56
- * account default. Sourced from the Cursor catalog survey
57
- * (stigmer-cloud _projects/2026-08/20260806.04.model-service-tier).
56
+ * account default. Sourced from a survey of the Cursor catalog (2026-08).
58
57
  */
59
58
  const FAST_PARAM_ID = "fast";
60
59
  const THINKING_PARAM_ID = "thinking";
@@ -0,0 +1,188 @@
1
+ /**
2
+ * A Cursor sub-agent's transcript, from the `task` tool's completed result to
3
+ * the canonical events that fold it (`harness/transcript/events.ts`), scoped
4
+ * to the sub-agent's own `subAgentId`.
5
+ *
6
+ * WHY THE TRANSCRIPT ARRIVES AS A BLOB. The Cursor SDK returns sub-agent work
7
+ * inside the `task` tool's completed event, not as streaming events with a
8
+ * distinct agent id. Re-verified 2026-08-23 on the pinned SDK (1.0.13) AND the
9
+ * latest (1.0.28), including the write side (stigmer/stigmer#839): an injected
10
+ * platform.eventStore/eventNotifier receives parent events only on 1.0.13 and
11
+ * is bypassed entirely on 1.0.28 (persistence moved into the executor daemon's
12
+ * own state dir); zero events reach the parent's run.stream() mid-task; the
13
+ * agentId in the task args is not a platform-store agent id at all, so it can
14
+ * never be addressable via Agent.listRuns / Agent.getRun (this is WHY the
15
+ * 2026-07-02 read-side polls all returned not-found). On 1.0.28 the child
16
+ * transcript lands at a deterministic path knowable at spawn
17
+ * (~/.cursor/projects/<slug>/agent-transcripts/<parentId>/subagents/<argsAgentId>.jsonl)
18
+ * but is flushed only at completion — verified with 200ms sampling across a
19
+ * full sub-agent run. Live nested visibility is therefore still an upstream
20
+ * SDK limitation — do not try to fake it here; the UI shows an elapsed-time
21
+ * affordance instead (SubAgentSection). This is Cursor's timing — the
22
+ * sub-agent's rows exist only at completion — and it stays Cursor's.
23
+ *
24
+ * THE SHAPE. The result is `{ status: "success", value: { conversationSteps } }`
25
+ * (or a bare `{ conversationSteps }`), where each ConversationStep is a
26
+ * protobuf-oneof object keyed DIRECTLY by its kind — there is NO
27
+ * `{ type, message }` envelope in production blobs, though the legacy `type`
28
+ * form is still read:
29
+ * - { thinkingMessage: { text, thinkingDurationMs? } }
30
+ * - { assistantMessage: { text } }
31
+ * - { toolCall: { toolCallId, <kind>ToolCall: { args, result } } }
32
+ * The tool family is the lone `<kind>ToolCall` sibling of `toolCallId`
33
+ * (`readToolCall`, `globToolCall`, `grepToolCall`, `shellToolCall`, …); the bare
34
+ * tool name is the suffix-stripped key, which feeds the shared `classifyTool`
35
+ * exactly like a top-level call. `result` is itself a oneof
36
+ * `{ success | error | permissionDenied | rejected }`. This is deliberately
37
+ * key-driven rather than an enumerated switch, so a new tool family the SDK
38
+ * adds surfaces automatically instead of being dropped. History: an earlier
39
+ * revision parsed a `{ type: "toolCall", message: { type, args, result } }`
40
+ * envelope that never appears in the real blob, so every sub-agent tool call
41
+ * was silently discarded and the UI showed a sub-agent that "did nothing".
42
+ *
43
+ * WHAT THIS MODULE EMITS, AND WHY EVENTS. Until #1097 this parser built
44
+ * `AgentMessage` protos itself (the conversation-steps extractor in the accumulator)
45
+ * — a third copy of the folding rule, whose message boundary drifted from the
46
+ * root's until then. Now each step becomes the events any harness's translator
47
+ * would emit for the same thing, and the shared `TranscriptBuilder` folds them
48
+ * with the root's own rules: an `assistantMessage` step is its own message
49
+ * (`runId` `<subAgentId>:step:<i>`, so two consecutive steps never merge); a
50
+ * `thinkingMessage` step a THINKING row under the same key; a `toolCall` step
51
+ * a `tool_started` then a `tool_finished`/`tool_error`, which the builder
52
+ * attaches to the transcript's current AI message (the assistant step that
53
+ * proposed it) or an empty one when there is none. Unknown step
54
+ * kinds and empty texts are skipped for forward compatibility. The rows carry
55
+ * no attribution or provenance (#1133).
56
+ *
57
+ * The `task` row's own `tool_finished` and the sub-agent's `sub_agent_finished`
58
+ * are the translator's (`translator.ts`); this module answers only "what
59
+ * happened inside".
60
+ */
61
+
62
+ import type { TranscriptEvent } from "../../harness/transcript/events.js";
63
+ import { canonicalizeImageResult } from "./tool-result.js";
64
+
65
+ /**
66
+ * The failure branches of a sub-agent tool call's `result` oneof. A completion
67
+ * is `{ success: ... }`; every other branch is a non-completion the UI must show
68
+ * as failed — an errored read/glob/grep (`error`), or a shell the approval gate
69
+ * stopped (`permissionDenied` / `rejected`).
70
+ */
71
+ const SUBAGENT_TOOL_RESULT_FAILURE_KEYS: ReadonlySet<string> = new Set([
72
+ "error",
73
+ "permissionDenied",
74
+ "rejected",
75
+ ]);
76
+
77
+ /** The canonical events for one sub-agent's completed `conversationSteps`, all scoped to `subAgentId`. */
78
+ export function subAgentStepEvents(result: unknown, subAgentId: string): TranscriptEvent[] {
79
+ const steps = conversationStepsOf(result);
80
+ const out: TranscriptEvent[] = [];
81
+ for (const [index, step] of steps.entries()) {
82
+ if (step == null || typeof step !== "object") continue;
83
+ const s = step as Record<string, unknown>;
84
+ const type = s.type as string | undefined;
85
+ const runId = `${subAgentId}:step:${index}`;
86
+
87
+ if (type === "thinkingMessage" || s.thinkingMessage != null) {
88
+ const text = stepText(type === "thinkingMessage" ? s.message : s.thinkingMessage);
89
+ if (text) {
90
+ out.push({ kind: "message_start", runId, subAgentId });
91
+ out.push({ kind: "reasoning_delta", runId, text, subAgentId });
92
+ out.push({ kind: "message_finish", runId, subAgentId });
93
+ }
94
+ } else if (type === "assistantMessage" || s.assistantMessage != null) {
95
+ const text = stepText(type === "assistantMessage" ? s.message : s.assistantMessage);
96
+ if (text) {
97
+ out.push({ kind: "message_start", runId, subAgentId });
98
+ out.push({ kind: "text_delta", runId, text, subAgentId });
99
+ out.push({ kind: "message_finish", runId, subAgentId });
100
+ }
101
+ } else if (s.toolCall != null) {
102
+ out.push(...subAgentToolCallEvents(s.toolCall, index, subAgentId));
103
+ }
104
+ }
105
+ return out;
106
+ }
107
+
108
+ /** The `conversationSteps` array from the task result's envelope, or none. */
109
+ function conversationStepsOf(result: unknown): unknown[] {
110
+ if (result == null || typeof result !== "object") return [];
111
+ const r = result as Record<string, unknown>;
112
+ const value = r.value ?? r;
113
+ if (value == null || typeof value !== "object") return [];
114
+ const steps = (value as Record<string, unknown>).conversationSteps;
115
+ return Array.isArray(steps) ? steps : [];
116
+ }
117
+
118
+ function stepText(message: unknown): string {
119
+ if (message == null || typeof message !== "object") return "";
120
+ const text = (message as Record<string, unknown>).text;
121
+ return typeof text === "string" ? text : "";
122
+ }
123
+
124
+ /**
125
+ * One `toolCall` step as a started row and its outcome. The SDK's real call id
126
+ * keeps the row stable across resumes and distinct from its siblings; a
127
+ * synthetic `sub-<name>-<stepIndex>` stands in only when the SDK omits one.
128
+ * A step with no `<kind>ToolCall` key (malformed or forward-incompatible) emits
129
+ * nothing rather than a blank, nameless row.
130
+ */
131
+ function subAgentToolCallEvents(toolCall: unknown, stepIndex: number, subAgentId: string): TranscriptEvent[] {
132
+ if (toolCall == null || typeof toolCall !== "object") return [];
133
+ const obj = toolCall as Record<string, unknown>;
134
+
135
+ const kindKey = Object.keys(obj).find((k) => k !== "toolCallId" && k.endsWith("ToolCall"));
136
+ if (!kindKey) return [];
137
+
138
+ const name = kindKey.slice(0, -"ToolCall".length);
139
+ const inner = obj[kindKey] != null && typeof obj[kindKey] === "object"
140
+ ? (obj[kindKey] as Record<string, unknown>)
141
+ : {};
142
+ const callId = typeof obj.toolCallId === "string" && obj.toolCallId
143
+ ? obj.toolCallId
144
+ : `sub-${name}-${stepIndex}`;
145
+ const input = inner.args != null && typeof inner.args === "object"
146
+ ? (inner.args as Record<string, unknown>)
147
+ : {};
148
+
149
+ const outcome = interpretSubAgentToolResult(inner.result);
150
+ return [
151
+ { kind: "tool_started", callId, name, input, mcpServerSlug: "", subAgentId },
152
+ outcome.status === "completed"
153
+ ? { kind: "tool_finished", callId, result: outcome.result, subAgentId }
154
+ : { kind: "tool_error", callId, message: outcome.error, subAgentId },
155
+ ];
156
+ }
157
+
158
+ /**
159
+ * A sub-agent tool call's `result` oneof as an outcome: `success` → completed
160
+ * with the serialized payload (a screenshot is canonicalized the same way as a
161
+ * top-level result); any failure branch → failed with the serialized detail
162
+ * (`error` alone — never a duplicate in `result`). An absent result is
163
+ * a completed call with no output — the SDK omits `result` for a call that
164
+ * reports nothing; an unknown oneof branch is surfaced as a completed result
165
+ * rather than dropped.
166
+ */
167
+ export function interpretSubAgentToolResult(result: unknown):
168
+ | { status: "completed"; result: string }
169
+ | { status: "failed"; error: string } {
170
+ if (result == null || typeof result !== "object") {
171
+ return { status: "completed", result: "" };
172
+ }
173
+ const r = result as Record<string, unknown>;
174
+
175
+ if ("success" in r) {
176
+ const val = r.success;
177
+ const str = canonicalizeImageResult(val) ?? (typeof val === "string" ? val : JSON.stringify(val));
178
+ return { status: "completed", result: str };
179
+ }
180
+
181
+ const failKey = Object.keys(r).find((k) => SUBAGENT_TOOL_RESULT_FAILURE_KEYS.has(k));
182
+ if (failKey) {
183
+ const val = r[failKey];
184
+ return { status: "failed", error: typeof val === "string" ? val : JSON.stringify(val) };
185
+ }
186
+
187
+ return { status: "completed", result: JSON.stringify(r) };
188
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * The Cursor harness's rendering of a tool result into the one string a
3
+ * transcript row carries — the translator's half of `tool_finished.result`
4
+ * (`harness/transcript/events.ts`): the engine's output envelope is the
5
+ * harness's to unwrap, the builder stores what it is handed, and the persist
6
+ * chokepoint bounds it. Native's twin is
7
+ * `extractToolResult` in `execute-deep-agent/translator.ts` (the LangChain
8
+ * ToolMessage envelope and the LangGraph Command).
9
+ *
10
+ * Its own module because two readers need it — the translator for a root
11
+ * row's result, `sub-agent-steps.ts` for a sub-agent's — and the second would
12
+ * otherwise import the first, which imports the second. Moved from
13
+ * `message-translator.ts` verbatim.
14
+ */
15
+
16
+ /**
17
+ * Normalize a tool_call event result into a string for the ToolCall proto.
18
+ * Returns "" for an absent result so callers can treat "no result yet" and
19
+ * "empty result" uniformly (e.g. to avoid clobbering a captured result).
20
+ *
21
+ * The one non-passthrough case is a multimodal MCP result (e.g. a computer-use
22
+ * screenshot): see {@link canonicalizeImageResult}. Everything else is the
23
+ * string as-is, or a whole-value JSON.stringify — byte-identical to before.
24
+ */
25
+ export function toResultString(result: unknown): string {
26
+ if (result == null) return "";
27
+ if (typeof result === "string") return result;
28
+ const canonical = canonicalizeImageResult(result);
29
+ if (canonical !== undefined) return canonical;
30
+ return JSON.stringify(result);
31
+ }
32
+
33
+ /**
34
+ * Re-emit a Cursor MCP result that carries an image block as the canonical
35
+ * top-level content-block array the persist-time offload understands.
36
+ *
37
+ * The Cursor SDK wraps an MCP tool result as `{ status, value: { content: [...] } }`
38
+ * (or a bare `{ content: [...] }`), where an image block is
39
+ * `{ image: { data, mimeType } }` and `data` is a Node Buffer-JSON
40
+ * (`{ type:"Buffer", data:number[] }`). Persisting that envelope verbatim buries
41
+ * the image where `detectImagePayload`/`contentBlocks` (shared/status-offload.ts)
42
+ * cannot see it, so the screenshot lands as `text/plain` instead of a renderable
43
+ * `ToolCallOutputRef`.
44
+ *
45
+ * This mirrors `serializeToolContent` in the deep-agent path
46
+ * (harness/transcript/tool-result.ts): the harness adapter normalizes
47
+ * its own wire shape into the canonical array
48
+ * `[{ type:"text", text }, { type:"image", data:<base64>, mimeType }]`
49
+ * so the shared offload stays harness-agnostic (its envelope handling is
50
+ * documented there as insurance, not the primary path). Buffer-JSON is decoded
51
+ * to base64 here so the bloated byte-array never propagates into the status.
52
+ *
53
+ * Returns undefined when there is no content array or no image block, so the
54
+ * caller falls back to its existing serialization (no change for text/error
55
+ * results).
56
+ */
57
+ export function canonicalizeImageResult(result: unknown): string | undefined {
58
+ if (result == null || typeof result !== "object") return undefined;
59
+ const blocks = resultContentBlocks(result as Record<string, unknown>);
60
+ if (!blocks) return undefined;
61
+
62
+ const canonical: Array<Record<string, unknown>> = [];
63
+ let sawImage = false;
64
+ for (const block of blocks) {
65
+ if (!block || typeof block !== "object") continue;
66
+ const b = block as Record<string, unknown>;
67
+
68
+ if (b.image && typeof b.image === "object") {
69
+ const img = b.image as Record<string, unknown>;
70
+ const base64 = imageDataToBase64(img.data);
71
+ if (base64) {
72
+ const mimeType = typeof img.mimeType === "string" ? img.mimeType : "image/png";
73
+ canonical.push({ type: "image", data: base64, mimeType });
74
+ sawImage = true;
75
+ continue;
76
+ }
77
+ }
78
+
79
+ const text = blockText(b);
80
+ if (text !== undefined) canonical.push({ type: "text", text });
81
+ }
82
+
83
+ return sawImage ? JSON.stringify(canonical) : undefined;
84
+ }
85
+
86
+ /** Extract the content-block array from a Cursor result envelope or a bare one. */
87
+ function resultContentBlocks(obj: Record<string, unknown>): unknown[] | undefined {
88
+ const value = obj.value;
89
+ if (value && typeof value === "object" && Array.isArray((value as Record<string, unknown>).content)) {
90
+ return (value as Record<string, unknown>).content as unknown[];
91
+ }
92
+ if (Array.isArray(obj.content)) return obj.content;
93
+ return undefined;
94
+ }
95
+
96
+ /**
97
+ * Decode an image block's `data` to plain base64. Accepts a Node Buffer-JSON
98
+ * (`{ type:"Buffer", data:number[] }`, how the Cursor SDK serializes bytes), a
99
+ * `data:` URL, or an already-base64 string. Returns undefined for anything else.
100
+ */
101
+ function imageDataToBase64(data: unknown): string | undefined {
102
+ if (data && typeof data === "object") {
103
+ const d = data as Record<string, unknown>;
104
+ if (d.type === "Buffer" && Array.isArray(d.data)) {
105
+ try {
106
+ return Buffer.from(d.data as number[]).toString("base64");
107
+ } catch {
108
+ return undefined;
109
+ }
110
+ }
111
+ return undefined;
112
+ }
113
+ if (typeof data === "string" && data) {
114
+ const dataUrl = data.match(/^data:image\/[a-zA-Z0-9.+-]+;base64,([\s\S]+)$/);
115
+ return (dataUrl ? dataUrl[1] : data).replace(/\s+/g, "");
116
+ }
117
+ return undefined;
118
+ }
119
+
120
+ /** Extract the text from a Cursor content block: `{ text:{text} }` or `{ text }`. */
121
+ function blockText(b: Record<string, unknown>): string | undefined {
122
+ const t = b.text;
123
+ if (typeof t === "string") return t;
124
+ if (t && typeof t === "object" && typeof (t as Record<string, unknown>).text === "string") {
125
+ return (t as Record<string, unknown>).text as string;
126
+ }
127
+ return undefined;
128
+ }