@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
@@ -1,12 +1,13 @@
1
1
  /**
2
2
  * Unit tests for the streaming persist decision (issue #179), the shared
3
- * cadence rule the Cursor stream loop calls today and the turn runtime
4
- * takes over in S2 M3.
3
+ * cadence rule both adapters' stream loops read.
5
4
  *
6
- * Validates the converged cadence: discrete force-flush signals persist
5
+ * Validates the converged cadence: a discrete transcript change persists
7
6
  * immediately, while high-frequency token deltas ride the shared
8
7
  * StreamingUpdateScheduler's time cadence (rather than the old, time-blind
9
- * `eventCount % 20` gate that starved short turns).
8
+ * `eventCount % 20` gate that starved short turns). The signal is the one
9
+ * transcript builder's `dirty` flag (since #1097); until then three
10
+ * Cursor-named flags, two of them constant `false` on both loops.
10
11
  */
11
12
 
12
13
  import { describe, it, expect } from "vitest";
@@ -22,65 +23,50 @@ const CONFIG: StreamingConfig = {
22
23
  burstThreshold: 50,
23
24
  };
24
25
 
25
- const NO_FORCE = {
26
- deltaEnricherDirty: false,
27
- todosDirty: false,
28
- contentDirty: false,
29
- } as const;
30
-
31
26
  describe("shouldPersistStreamingStatus", () => {
32
27
  it("persists on the first event via the scheduler (kills the opaque-wait at turn start)", () => {
33
28
  const scheduler = new StreamingUpdateScheduler(CONFIG, 0);
34
- expect(shouldPersistStreamingStatus(NO_FORCE, scheduler, 1, 0)).toBe(true);
29
+ expect(shouldPersistStreamingStatus(false, scheduler, 1, 0)).toBe(true);
35
30
  });
36
31
 
37
- it("does not persist a sub-500ms token delta with no force signal", () => {
32
+ it("does not persist a sub-500ms token delta while the transcript is clean", () => {
38
33
  const scheduler = new StreamingUpdateScheduler(CONFIG, 0);
39
34
  scheduler.markUpdateSent(1, 0); // first flush already sent
40
35
 
41
36
  // 100ms later, one more delta event — too soon for the time cadence.
42
- expect(shouldPersistStreamingStatus(NO_FORCE, scheduler, 2, 100)).toBe(false);
37
+ expect(shouldPersistStreamingStatus(false, scheduler, 2, 100)).toBe(false);
43
38
  });
44
39
 
45
40
  it("persists a token delta once the 500ms cadence elapses", () => {
46
41
  const scheduler = new StreamingUpdateScheduler(CONFIG, 0);
47
42
  scheduler.markUpdateSent(1, 0);
48
43
 
49
- expect(shouldPersistStreamingStatus(NO_FORCE, scheduler, 2, 500)).toBe(true);
44
+ expect(shouldPersistStreamingStatus(false, scheduler, 2, 500)).toBe(true);
50
45
  });
51
46
 
52
- it.each([
53
- ["contentDirty (tool call / sub-agent)", { ...NO_FORCE, contentDirty: true }],
54
- ["todosDirty", { ...NO_FORCE, todosDirty: true }],
55
- ["deltaEnricherDirty (shell output)", { ...NO_FORCE, deltaEnricherDirty: true }],
56
- ])("force-flushes immediately on %s, bypassing the time cadence", (_label, signals) => {
47
+ it("flushes immediately when the transcript is dirty, bypassing the time cadence", () => {
57
48
  const scheduler = new StreamingUpdateScheduler(CONFIG, 0);
58
49
  scheduler.markUpdateSent(1, 0);
59
50
 
60
51
  // Only 1ms after the last flush: the scheduler alone would say no...
61
- expect(shouldPersistStreamingStatus(NO_FORCE, scheduler, 2, 1)).toBe(false);
62
- // ...but any discrete force signal flushes now.
63
- expect(shouldPersistStreamingStatus(signals, scheduler, 2, 1)).toBe(true);
52
+ expect(shouldPersistStreamingStatus(false, scheduler, 2, 1)).toBe(false);
53
+ // ...but a discrete transcript change flushes now.
54
+ expect(shouldPersistStreamingStatus(true, scheduler, 2, 1)).toBe(true);
64
55
  });
65
56
 
66
57
  // The #179 starvation scenario: a short turn of < 20 events. Under the old
67
58
  // `eventCount % 20` gate, a tool call appearing at event 3 (and completing at
68
59
  // event 4) would never be persisted until the unconditional final flush. With
69
- // the converged decision, the tool lifecycle force-flushes the instant it
70
- // happens, regardless of how few events the turn has.
60
+ // the converged decision, the tool lifecycle flushes the instant it happens,
61
+ // regardless of how few events the turn has.
71
62
  it("surfaces a tool call on a short (<20 event) turn", () => {
72
63
  const scheduler = new StreamingUpdateScheduler(CONFIG, 0);
73
64
  const flushes: number[] = [];
74
65
  let clock = 0;
75
66
 
76
67
  // Helper mirroring the loop: decide, then mark both clocks on a flush.
77
- const tick = (eventCount: number, contentDirty: boolean) => {
78
- const persist = shouldPersistStreamingStatus(
79
- { ...NO_FORCE, contentDirty },
80
- scheduler,
81
- eventCount,
82
- clock,
83
- );
68
+ const tick = (eventCount: number, transcriptDirty: boolean) => {
69
+ const persist = shouldPersistStreamingStatus(transcriptDirty, scheduler, eventCount, clock);
84
70
  if (persist) {
85
71
  flushes.push(eventCount);
86
72
  scheduler.markUpdateSent(eventCount, clock);
@@ -90,8 +76,8 @@ describe("shouldPersistStreamingStatus", () => {
90
76
 
91
77
  tick(1, false); // assistant delta — first-event flush
92
78
  tick(2, false); // thinking delta — within 500ms, no flush
93
- tick(3, true); // tool call starts — force-flush
94
- tick(4, true); // tool call completes — force-flush
79
+ tick(3, true); // tool call starts — the transcript is dirty, flush
80
+ tick(4, true); // tool call completes — dirty again, flush
95
81
  tick(5, false); // closing assistant delta — within 500ms, no flush
96
82
 
97
83
  // The tool lifecycle (events 3 and 4) is observed live; event 1 is the
@@ -2,7 +2,7 @@
2
2
  * The shared prompt glue (`shared/prompt-sections.ts`): the standing order,
3
3
  * the input-files lines, the skill selection and the also-available sentence
4
4
  * (the sentence's arms came from `skill-writer.test.ts`, retired with its
5
- * module at S3 M5). What each harness renders AROUND these is pinned whole by
5
+ * module in #1096). What each harness renders AROUND these is pinned whole by
6
6
  * the two builders' prompt goldens (`execute-deep-agent/__tests__/
7
7
  * prompt-goldens.test.ts`, `execute-cursor/__tests__/prompt-goldens.test.ts`);
8
8
  * this file pins the glue's own contract, harness-free.
@@ -0,0 +1,111 @@
1
+ /**
2
+ * The run credential's wire reader and its store (`run-credential.ts`,
3
+ * `run-credential-store.ts`).
4
+ *
5
+ * The property that matters is the last arm: two activities whose awaits
6
+ * interleave in one process each see their own credential and never the
7
+ * other's. That is what lets one shared `StigmerClient` — one per worker for
8
+ * the turn activities — present the right run's credential per request.
9
+ */
10
+
11
+ import { describe, expect, it } from "vitest";
12
+
13
+ import {
14
+ RUN_CREDENTIAL_HEADER,
15
+ RUN_CREDENTIAL_INPUT_KEY,
16
+ readRunCredentialFromInput,
17
+ } from "../run-credential.js";
18
+ import {
19
+ currentRunCredential,
20
+ withRunCredential,
21
+ } from "../run-credential-store.js";
22
+
23
+ describe("readRunCredentialFromInput", () => {
24
+ it("reads a non-empty string under the wire key", () => {
25
+ expect(
26
+ readRunCredentialFromInput({ [RUN_CREDENTIAL_INPUT_KEY]: "cred-1" }),
27
+ ).toBe("cred-1");
28
+ });
29
+
30
+ it("answers undefined for the positional string shape the turn activities also accept", () => {
31
+ expect(readRunCredentialFromInput("aex_123")).toBeUndefined();
32
+ });
33
+
34
+ it("answers undefined for a credential-less object — an older server's dispatch", () => {
35
+ expect(
36
+ readRunCredentialFromInput({ execution_id: "aex_123", thread_id: "" }),
37
+ ).toBeUndefined();
38
+ });
39
+
40
+ it("answers undefined for an empty string, null, undefined and a non-string value", () => {
41
+ expect(
42
+ readRunCredentialFromInput({ [RUN_CREDENTIAL_INPUT_KEY]: "" }),
43
+ ).toBeUndefined();
44
+ expect(readRunCredentialFromInput(null)).toBeUndefined();
45
+ expect(readRunCredentialFromInput(undefined)).toBeUndefined();
46
+ expect(
47
+ readRunCredentialFromInput({ [RUN_CREDENTIAL_INPUT_KEY]: 42 }),
48
+ ).toBeUndefined();
49
+ });
50
+
51
+ it("does not read the connect lane's camelCase per-call token", () => {
52
+ expect(
53
+ readRunCredentialFromInput({ executionContextToken: "connect-token" }),
54
+ ).toBeUndefined();
55
+ });
56
+
57
+ it("pins the wire vocabulary as bytes", () => {
58
+ expect(RUN_CREDENTIAL_INPUT_KEY).toBe("execution_context_token");
59
+ expect(RUN_CREDENTIAL_HEADER).toBe("stigmer-run-credential");
60
+ });
61
+ });
62
+
63
+ describe("run-credential store", () => {
64
+ it("is empty outside any activity", () => {
65
+ expect(currentRunCredential()).toBeUndefined();
66
+ });
67
+
68
+ it("is visible to everything the wrapped function awaits, and gone after", async () => {
69
+ let inner: string | undefined;
70
+ await withRunCredential("cred-a", async () => {
71
+ await Promise.resolve();
72
+ inner = await (async () => currentRunCredential())();
73
+ });
74
+ expect(inner).toBe("cred-a");
75
+ expect(currentRunCredential()).toBeUndefined();
76
+ });
77
+
78
+ it("is inherited by a promise created inside the scope and settled after it", async () => {
79
+ let detached: Promise<string | undefined> | undefined;
80
+ await withRunCredential("cred-b", async () => {
81
+ detached = new Promise((resolve) =>
82
+ setTimeout(() => resolve(currentRunCredential()), 5),
83
+ );
84
+ });
85
+ expect(await detached).toBe("cred-b");
86
+ });
87
+
88
+ it("never crosses between two activities whose awaits interleave", async () => {
89
+ const seen: Array<[string, string | undefined]> = [];
90
+ const activity = async (name: string, ticks: number) => {
91
+ for (let i = 0; i < ticks; i++) {
92
+ await new Promise((resolve) => setTimeout(resolve, 1));
93
+ seen.push([name, currentRunCredential()]);
94
+ }
95
+ };
96
+ await Promise.all([
97
+ withRunCredential("cred-1", () => activity("one", 4)),
98
+ withRunCredential("cred-2", () => activity("two", 4)),
99
+ activity("none", 4),
100
+ ]);
101
+ expect(seen.filter(([name]) => name === "one").map(([, c]) => c)).toEqual(
102
+ Array(4).fill("cred-1"),
103
+ );
104
+ expect(seen.filter(([name]) => name === "two").map(([, c]) => c)).toEqual(
105
+ Array(4).fill("cred-2"),
106
+ );
107
+ expect(seen.filter(([name]) => name === "none").map(([, c]) => c)).toEqual(
108
+ Array(4).fill(undefined),
109
+ );
110
+ });
111
+ });
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Unit tests for the shared turn-boundary flowed-row stamping
3
3
  * (`shared/tool-row.ts` `stampFlowedFileEditRows` /
4
- * `stampFlowedSubAgentFileEditRows`; the deep-agent's copy until S3 M4), with
4
+ * `stampFlowedSubAgentFileEditRows`; the deep-agent's copy until #1096), with
5
5
  * emphasis on the sub-agent path added by the DD-24 follow-up: sub-agent edit
6
6
  * rows fold into the parent turn's change set, so they carry the parent change
7
7
  * set id, scoped to this turn by tool-call-id novelty (they lack the
@@ -342,7 +342,7 @@ describe("offloadOversizedToolOutputs", () => {
342
342
  await offloadOversizedToolOutputs(status, ctx);
343
343
  expect(uploads).toHaveLength(1);
344
344
 
345
- // Simulate mergeToolCallEvent re-inflating the inline result with the SAME
345
+ // Simulate the builder's finish upsert re-inflating the inline result with the SAME
346
346
  // bytes on a subsequent persist; the ref's content hash still matches.
347
347
  status.messages[0].toolCalls[0].result = result;
348
348
  await offloadOversizedToolOutputs(status, ctx);
@@ -1,7 +1,6 @@
1
1
  import { describe, it, expect, vi, afterEach } from "vitest";
2
2
  import {
3
3
  StreamingUpdateScheduler,
4
- UpdateReason,
5
4
  loadStreamingConfig,
6
5
  type StreamingConfig,
7
6
  } from "../streaming-scheduler.js";
@@ -17,7 +16,7 @@ describe("StreamingUpdateScheduler", () => {
17
16
  it("always sends on first event", () => {
18
17
  const s = new StreamingUpdateScheduler(BASE_CONFIG, 0);
19
18
  expect(s.shouldSendUpdate(1, 0)).toBe(true);
20
- expect(s.updateReason).toBe(UpdateReason.FIRST_UPDATE);
19
+ expect(s.updateReason).toBe("first_update");
21
20
  });
22
21
 
23
22
  it("does not send if zero events processed", () => {
@@ -32,7 +31,7 @@ describe("StreamingUpdateScheduler", () => {
32
31
  s.markUpdateSent(0, 0);
33
32
 
34
33
  expect(s.shouldSendUpdate(1, 500)).toBe(true);
35
- expect(s.updateReason).toBe(UpdateReason.TIME_THRESHOLD);
34
+ expect(s.updateReason).toBe("time_threshold");
36
35
  });
37
36
 
38
37
  it("does not send before minInterval", () => {
@@ -40,7 +39,7 @@ describe("StreamingUpdateScheduler", () => {
40
39
  s.markUpdateSent(0, 0);
41
40
 
42
41
  expect(s.shouldSendUpdate(1, 499)).toBe(false);
43
- expect(s.updateReason).toBe(UpdateReason.NONE);
42
+ expect(s.updateReason).toBe("none");
44
43
  });
45
44
 
46
45
  it("does not send after minInterval with zero new events", () => {
@@ -57,7 +56,7 @@ describe("StreamingUpdateScheduler", () => {
57
56
  s.markUpdateSent(0, 0);
58
57
 
59
58
  expect(s.shouldSendUpdate(50, 100)).toBe(true);
60
- expect(s.updateReason).toBe(UpdateReason.BURST_PROTECTION);
59
+ expect(s.updateReason).toBe("burst_protection");
61
60
  });
62
61
 
63
62
  it("does not send at threshold - 1", () => {
@@ -74,7 +73,7 @@ describe("StreamingUpdateScheduler", () => {
74
73
  s.markUpdateSent(10, 0);
75
74
 
76
75
  expect(s.shouldSendUpdate(10, 5000)).toBe(true);
77
- expect(s.updateReason).toBe(UpdateReason.KEEPALIVE);
76
+ expect(s.updateReason).toBe("keepalive");
78
77
  });
79
78
 
80
79
  it("does not send keepalive before maxInterval", () => {
@@ -91,7 +90,7 @@ describe("StreamingUpdateScheduler", () => {
91
90
  s.markUpdateSent(10, 1000);
92
91
 
93
92
  expect(s.shouldSendUpdate(11, 1500)).toBe(true);
94
- expect(s.updateReason).toBe(UpdateReason.TIME_THRESHOLD);
93
+ expect(s.updateReason).toBe("time_threshold");
95
94
 
96
95
  s.markUpdateSent(11, 1500);
97
96
 
@@ -125,7 +124,7 @@ describe("StreamingUpdateScheduler", () => {
125
124
  const s = new StreamingUpdateScheduler(BASE_CONFIG, 0);
126
125
  // First check with event and enough time — should be FIRST_UPDATE, not TIME_THRESHOLD
127
126
  expect(s.shouldSendUpdate(1, 600)).toBe(true);
128
- expect(s.updateReason).toBe(UpdateReason.FIRST_UPDATE);
127
+ expect(s.updateReason).toBe("first_update");
129
128
  });
130
129
 
131
130
  it("time_threshold takes priority over burst_protection", () => {
@@ -134,7 +133,7 @@ describe("StreamingUpdateScheduler", () => {
134
133
 
135
134
  // Both time and burst conditions met — time wins
136
135
  expect(s.shouldSendUpdate(50, 500)).toBe(true);
137
- expect(s.updateReason).toBe(UpdateReason.TIME_THRESHOLD);
136
+ expect(s.updateReason).toBe("time_threshold");
138
137
  });
139
138
  });
140
139
  });
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Unit tests for applyTodoUpdate — the harness-agnostic to-do map projection
3
- * shared by the Cursor TodoTracker and the native v2/v3 status builders.
3
+ * the one transcript builder projects a todo write through, for both harnesses.
4
4
  *
5
5
  * These pin the exact mapping contract (status coercion, id synthesis,
6
6
  * created_at preservation, merge vs. full-replace, clear-on-empty, defensive
@@ -382,7 +382,7 @@ describe("collectSettledToolCallIds", () => {
382
382
  // scoping them as this-turn would mis-attribute a dead call to the
383
383
  // resuming turn's change set. (The Cursor monotonic guard makes the
384
384
  // opposite call for the same status so a replayed event can still advance
385
- // the row; see isTerminalToolStatus in message-translator.ts.)
385
+ // the row; see isSettled in harness/transcript/builder.ts.)
386
386
  const ids = collectSettledToolCallIds([
387
387
  msgWith("tc-interrupted", ToolCallStatus.TOOL_CALL_INTERRUPTED),
388
388
  ]);
@@ -15,6 +15,9 @@
15
15
  * then the control planes; once both are everywhere, drop the positional branch
16
16
  * (and the `string` arms below).
17
17
  */
18
+
19
+ import type { RUN_CREDENTIAL_INPUT_KEY } from "./run-credential.js";
20
+
18
21
  export interface ExecuteActivityInput {
19
22
  readonly execution_id: string;
20
23
  readonly thread_id: string;
@@ -27,8 +30,26 @@ export interface ExecuteActivityInput {
27
30
  * from it. Absent on the legacy positional wire shape (defaults to 0).
28
31
  */
29
32
  readonly turn_seq?: number;
33
+ /**
34
+ * The run credential the server minted for this execution at dispatch,
35
+ * handed on from the workflow input; absent when the dispatch carried none
36
+ * (an older server; the cloud). Not normalized here and never read by an
37
+ * activity: the activity boundary enters it into the run-credential store
38
+ * before the activity runs (`interceptors/run-credential-activity.ts`), and
39
+ * the control-plane client presents it per request (`run-credential.ts`).
40
+ */
41
+ readonly execution_context_token?: string;
30
42
  }
31
43
 
44
+ /**
45
+ * Compile-time fence: the key the boundary reads
46
+ * (`RUN_CREDENTIAL_INPUT_KEY`) is a key of this input. The type keeps the
47
+ * literal so the wire shape stays readable; this line fails to type-check the
48
+ * day the two disagree.
49
+ */
50
+ type _RunCredentialKeyIsOnTheWire =
51
+ ExecuteActivityInput[typeof RUN_CREDENTIAL_INPUT_KEY];
52
+
32
53
  export interface NormalizedActivityInput {
33
54
  readonly executionId: string;
34
55
  readonly threadId: string;
@@ -466,3 +466,98 @@ export function resolveApprovalMessage(
466
466
  return JSON.stringify(value);
467
467
  });
468
468
  }
469
+
470
+ // ── The gate's decision ─────────────────────────────────────────────
471
+
472
+ /**
473
+ * THE approval-message template per mutating built-in category — the one
474
+ * table both harnesses word their approval cards from (since #1097).
475
+ * Keyed by category (not raw tool name) so every alias of a mutation renders
476
+ * one message; placeholders resolve against the stream arg shape
477
+ * (`path`/`command`; `resolveApprovalMessage`). The native gate decides with
478
+ * it (`resolveToolApproval`), the Cursor translator words its `gate` from it
479
+ * (`execute-cursor/approval-policy.ts` `getBuiltInApprovalMessage`), and the
480
+ * Cursor boundary resolves a denied call's message through the same path.
481
+ *
482
+ * Until then the Cursor harness carried a table of its own and the two differed
483
+ * by a word — `shell` read "Run command" there and "Execute command" here.
484
+ * Unified on the plainer word: a user reads "Run command" and knows
485
+ * what is being asked. Known and deliberately left (#1112):
486
+ * `write` resolves `{{args.path}}`, while deepagents' file tools send
487
+ * `file_path`, so a gated native write reads "Write file: <unknown>".
488
+ */
489
+ export const CATEGORY_APPROVAL_MESSAGE: Record<ToolApprovalCategory, string> = {
490
+ write: "Write file: {{args.path}}",
491
+ delete: "Delete: {{args.path}}",
492
+ shell: "Run command: {{args.command}}",
493
+ };
494
+
495
+ /** What the gate decides for one call: whether it waits, the message the card shows, and which layer said so. */
496
+ export interface ApprovalRequirement {
497
+ readonly requiresApproval: boolean;
498
+ readonly message: string;
499
+ /** Which policy layer determined this verdict — stamped on the shadow receipt. */
500
+ readonly source: PolicySource;
501
+ }
502
+
503
+ /**
504
+ * THE approval decision for one tool call — the same function the native gate
505
+ * (`middleware/approval-gate.ts`) interrupts on and the native translator
506
+ * reports as `tool_started.gate`, so the row can never disagree with the gate
507
+ * about whether a call waits (since #1097; until then the transcript
508
+ * builder carried its own weaker copy that gated MCP tools only). Its
509
+ * read-side twin is {@link resolveApprovalProvenance}, which answers "which
510
+ * layer governs this call" for EVERY call, gated or not.
511
+ *
512
+ * MCP tools stay governed by the connect-flow classifier + four-level policy
513
+ * chain. The policy map carries only the tools that REQUIRE approval, so an
514
+ * absent entry means the classifier already auto-approved it — fail-OPEN is
515
+ * correct here (a fail-closed default would re-gate everything the classifier
516
+ * cleared). A server-scoped lease surfaces as an absent entry too: the leased
517
+ * server's tools are dropped from `policies` upstream (`mergeApprovalPolicies`),
518
+ * so a lease-cleared MCP tool takes the same auto-approve path (its receipt
519
+ * therefore reads classifier_default rather than approval_lease; a faithful
520
+ * per-server lease provenance would need the lease set threaded here and is
521
+ * deferred with the rest of the persisted-receipt work).
522
+ *
523
+ * Built-in/platform tools: gate exactly the mutating categories through the
524
+ * shared classifier — fail-CLOSED for the mutating set (write/edit/delete/shell
525
+ * require approval), fail-open for read-only and unclassified built-ins. A
526
+ * run-lifetime category lease (the user chose "approve all <category>" earlier
527
+ * in this run) auto-approves every built-in of that category for the rest of
528
+ * the run — the scoped successor to auto-approve-all.
529
+ */
530
+ export function resolveToolApproval(
531
+ toolName: string,
532
+ serverSlug: string,
533
+ args: Record<string, unknown>,
534
+ policies: ReadonlyMap<string, MergedToolPolicy>,
535
+ leasedCategories: ReadonlySet<ToolApprovalCategory>,
536
+ ): ApprovalRequirement {
537
+ if (serverSlug) {
538
+ const key = `${serverSlug}/${toolName}`;
539
+ const policy = policies.get(key);
540
+ if (policy) {
541
+ return {
542
+ requiresApproval: policy.requiresApproval,
543
+ message: resolveApprovalMessage(policy.approvalMessage, toolName, args),
544
+ source: policy.source,
545
+ };
546
+ }
547
+ return { requiresApproval: false, message: "", source: "classifier_default" };
548
+ }
549
+
550
+ const category = toolApprovalCategory(toolName);
551
+ if (category) {
552
+ if (leasedCategories.has(category)) {
553
+ return { requiresApproval: false, message: "", source: "approval_lease" };
554
+ }
555
+ return {
556
+ requiresApproval: true,
557
+ message: resolveApprovalMessage(CATEGORY_APPROVAL_MESSAGE[category], toolName, args),
558
+ source: "builtin_category",
559
+ };
560
+ }
561
+
562
+ return { requiresApproval: false, message: "", source: "builtin_category" };
563
+ }
@@ -8,9 +8,29 @@
8
8
  * JSON: the per-tool offload does not touch it, and the aggregate size backstop
9
9
  * would replace an oversized preview with an unparseable marker.
10
10
  *
11
- * This module is the single home for arg sanitization shared by both harnesses
12
- * (native re-exports {@link sanitizeArgsPreview} from its status builders; the
13
- * Cursor gate path uses {@link buildElidedArgsPreview}).
11
+ * ONE preview rule for every row (since #1097): the transcript builder
12
+ * stamps every tool row's preview through {@link buildElidedArgsPreview} over
13
+ * {@link SALIENT_ARG_FIELDS}, as `message.proto` promises — sanitized,
14
+ * redacted, at creation, for inline visibility. Until then there were two
15
+ * rules: native stamped a whole-string-truncating `sanitizeArgsPreview` on
16
+ * gated rows only (a preview that could truncate to invalid JSON, acceptable
17
+ * only because native's resume never re-parsed it), and Cursor's stream path
18
+ * stamped `JSON.stringify(args)` unredacted. Both are
19
+ * gone; this module holds the one builder and the one salient list.
20
+ *
21
+ * THE PREVIEW NEVER CARRIES A VALUE IT CANNOT CARRY WHOLE. A non-salient
22
+ * string over the per-value cap is left out of the preview — not replaced by
23
+ * an in-band marker. The marker this module wrote until #1097 (`"[381
24
+ * chars]"`) was a string no reader could tell from content: the approval gate
25
+ * rendered it as the file the user was asked to approve (stigmer#1107). An
26
+ * absent key is the out-of-band signal every reader already handles — a
27
+ * surface that needs the whole value reads the row's `args`, the way the
28
+ * gate does now; the codebase's precedent for "content not included" is a
29
+ * typed fact on the wire (file review's `FileReviewBlockReason`), never a
30
+ * display string, and the approval projection gaining such a fact is a
31
+ * follow-up of its own. The cost, named: the CLI's and ink's one-line preview
32
+ * loses the value's size, and Cursor's recovery digest reads `tool({})` for
33
+ * an MCP tool whose only argument is oversized.
14
34
  */
15
35
 
16
36
  /**
@@ -22,24 +42,27 @@ export const SENSITIVE_ARG_KEYS: ReadonlySet<string> = new Set([
22
42
  "credentials", "auth", "authorization",
23
43
  ]);
24
44
 
25
- /** Whole-preview length cap for {@link sanitizeArgsPreview} (native). */
26
- export const MAX_ARGS_PREVIEW_LENGTH = 500;
27
-
28
45
  /**
29
- * Sanitize args into a compact preview string (native harness behavior).
30
- *
31
- * Redacts sensitive keys, then truncates the whole JSON to a fixed length. The
32
- * truncation can yield invalid JSON, which is acceptable for the native harness
33
- * (its resume model keys on `tool_call_id`, never on a re-parsed preview). The
34
- * Cursor gate path must instead use {@link buildElidedArgsPreview}, which keeps
35
- * the JSON valid and preserves the salient identity fields.
46
+ * Top-level tool-argument fields, in priority order, that identify the specific
47
+ * resource a built-in tool acts on — the values a preview must carry VERBATIM,
48
+ * however long, because an identity is parsed back out of them. The list
49
+ * deliberately spans BOTH taxonomies' arg shapes: Cursor's hook input names a
50
+ * file `file_path` and its stream names it `path`; deepagents' file tools send
51
+ * `file_path`; both name a shell command `command`. Extracting the same
52
+ * resource VALUE on both sides (the absolute path / the command string) is
53
+ * what lets the Cursor hook-recorded denial token equal the stream-computed
54
+ * token. Authored here once (moved from `execute-cursor/approval-policy.ts`
55
+ * in #1097) and injected into the generated preToolUse hook script
56
+ * so the runner and the hook never disagree on which field to match.
36
57
  */
58
+ export const SALIENT_ARG_FIELDS = ["file_path", "path", "target_notebook", "command"] as const;
59
+
37
60
  /**
38
61
  * Redact secret-keyed values (see {@link SENSITIVE_ARG_KEYS}), preserving every
39
- * other entry verbatim. The shared first step of both preview builders, and the
40
- * shape stamped as `args` on interrupt-placeholder tool calls (issue #754's
41
- * header fix): full enough for the UI's path/primary-arg extraction, never
42
- * carrying a secret value.
62
+ * other entry verbatim. The first step of the preview builder, and the shape
63
+ * stamped as `args` on a proposed row the harness recovered from its engine's
64
+ * state (issue #754's header fix): full enough for the UI's path/primary-arg
65
+ * extraction, never carrying a secret value.
43
66
  */
44
67
  export function redactSensitiveArgs(
45
68
  args: Record<string, unknown>,
@@ -51,18 +74,6 @@ export function redactSensitiveArgs(
51
74
  return redacted;
52
75
  }
53
76
 
54
- export function sanitizeArgsPreview(args: Record<string, unknown>): string {
55
- const sanitized = redactSensitiveArgs(args);
56
- try {
57
- const json = JSON.stringify(sanitized);
58
- return json.length > MAX_ARGS_PREVIEW_LENGTH
59
- ? json.slice(0, MAX_ARGS_PREVIEW_LENGTH) + "…"
60
- : json;
61
- } catch {
62
- return "";
63
- }
64
- }
65
-
66
77
  /** Per-string-value cap for {@link buildElidedArgsPreview}. */
67
78
  const MAX_PREVIEW_VALUE_LENGTH = 200;
68
79
 
@@ -70,18 +81,19 @@ const MAX_PREVIEW_VALUE_LENGTH = 200;
70
81
  * Build a compact, ALWAYS-VALID `args_preview` from a tool call's full,
71
82
  * authoritative arguments.
72
83
  *
73
- * Unlike {@link sanitizeArgsPreview} (which truncates the whole string, possibly
74
- * to invalid JSON), this elides oversized string *values* in place — preserving
75
- * every key and the JSON structure. Two invariants make it safe for the Cursor
76
- * gate path:
84
+ * Leaves oversized string *values* out — every other key and the JSON
85
+ * structure kept — rather than truncating the whole string. Two invariants
86
+ * make it safe for the Cursor gate path:
77
87
  * - It NEVER elides a salient field (the resume grant's identity — the file
78
88
  * path or shell command — is parsed back out of this preview, so it must
79
89
  * survive verbatim).
80
90
  * - It redacts secret keys.
81
91
  *
92
+ * For short, secret-free args the output is exactly `JSON.stringify(args)`.
82
93
  * The heavy content (a whole-file body, a large diff) lives on `file_changes`
83
94
  * (offloaded to a ref when large) and `args` (bounded by the size backstop), so
84
- * the preview itself stays small even for a multi-MB write.
95
+ * the preview itself stays small even for a multi-MB write. Unserializable
96
+ * args (a cycle) yield `""`, never a thrown row.
85
97
  *
86
98
  * @param args the full tool arguments
87
99
  * @param salientFields keys whose values must be preserved verbatim (identity)
@@ -94,15 +106,12 @@ export function buildElidedArgsPreview(
94
106
  for (const [key, value] of Object.entries(args)) {
95
107
  if (SENSITIVE_ARG_KEYS.has(key.toLowerCase())) {
96
108
  out[key] = "[REDACTED]";
97
- } else if (
98
- !salientFields.includes(key) &&
99
- typeof value === "string" &&
100
- value.length > MAX_PREVIEW_VALUE_LENGTH
101
- ) {
102
- out[key] = `[${value.length} chars]`;
103
- } else {
104
- out[key] = value;
109
+ continue;
105
110
  }
111
+ const oversized = typeof value === "string" && value.length > MAX_PREVIEW_VALUE_LENGTH;
112
+ // An oversized non-salient value is left out, never marked (see the header).
113
+ if (oversized && !salientFields.includes(key)) continue;
114
+ out[key] = value;
106
115
  }
107
116
  try {
108
117
  return JSON.stringify(out);
@@ -24,7 +24,7 @@
24
24
  * written into the user's own tree would be committed to the session's
25
25
  * write-back branch on completion (`git add -A`), and every real producer —
26
26
  * the CLI's directory attachments, the approved plan the console mounts —
27
- * already stays inside `inputs/` (S3 M1, Q-M1-2; the proto's `/workspace/…`
27
+ * already stays inside `inputs/` (since #1096; the proto's `/workspace/…`
28
28
  * example is a doc issue). The prompt's `<input_files>` section and every
29
29
  * path-derived directive are built from the RESOLVED paths, so prompt and
30
30
  * filesystem can never disagree.
@@ -52,9 +52,9 @@
52
52
  * {@link AttachmentResolutionError}; an archive that fails its guards
53
53
  * aborts with the guard's own `AttachmentValidationError`.
54
54
  *
55
- * Until S3 M1 this resolver ignored `mountPath` and could not extract; the
56
- * native harness's `attachment-injector.ts` did both and was retired at S3
57
- * M2b for this one pipeline (Q-S3-14).
55
+ * Until #1096 this resolver ignored `mountPath` and could not extract; the
56
+ * native harness's `attachment-injector.ts` did both and was retired in that
57
+ * PR for this one pipeline.
58
58
  */
59
59
 
60
60
  import { mkdir, copyFile, readFile, stat, writeFile } from "node:fs/promises";
@@ -25,8 +25,8 @@
25
25
  * "the manifest promised a file extraction cannot find" is unrepresentable.
26
26
  * The WRITE of an extracted entry is the caller's: the attachment resolver
27
27
  * writes under the session's platform dir (`attachment-resolver.ts`), the
28
- * one caller since S3 M2b retired the native injector. Moved here from that
29
- * injector at S3 M1 (Q-S3-14) so the guards have one home.
28
+ * one caller since #1096 retired the native injector. Moved here from that
29
+ * injector in the same PR so the guards have one home.
30
30
  */
31
31
 
32
32
  import { createInflateRaw } from "node:zlib";