@stigmer/runner 3.0.9-dev.20260615153829 → 3.1.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 (329) hide show
  1. package/dist/.build-fingerprint +1 -1
  2. package/dist/__test-utils__/approval-contract/types.d.ts +174 -0
  3. package/dist/__test-utils__/approval-contract/types.js +24 -0
  4. package/dist/__test-utils__/approval-contract/types.js.map +1 -0
  5. package/dist/activities/call-agent-status.d.ts +19 -1
  6. package/dist/activities/call-agent-status.js +64 -5
  7. package/dist/activities/call-agent-status.js.map +1 -1
  8. package/dist/activities/call-llm.js +19 -53
  9. package/dist/activities/call-llm.js.map +1 -1
  10. package/dist/activities/classify-tool-approvals.d.ts +24 -0
  11. package/dist/activities/classify-tool-approvals.js +69 -17
  12. package/dist/activities/classify-tool-approvals.js.map +1 -1
  13. package/dist/activities/discover-mcp-server.d.ts +7 -0
  14. package/dist/activities/discover-mcp-server.js +11 -1
  15. package/dist/activities/discover-mcp-server.js.map +1 -1
  16. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.d.ts +140 -0
  17. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js +130 -0
  18. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js.map +1 -0
  19. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.d.ts +18 -0
  20. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js +123 -0
  21. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js.map +1 -0
  22. package/dist/activities/execute-cursor/approval-policy.d.ts +17 -61
  23. package/dist/activities/execute-cursor/approval-policy.js +8 -120
  24. package/dist/activities/execute-cursor/approval-policy.js.map +1 -1
  25. package/dist/activities/execute-cursor/approval-state.d.ts +219 -9
  26. package/dist/activities/execute-cursor/approval-state.js +233 -17
  27. package/dist/activities/execute-cursor/approval-state.js.map +1 -1
  28. package/dist/activities/execute-cursor/capture-flow.d.ts +127 -0
  29. package/dist/activities/execute-cursor/capture-flow.js +234 -0
  30. package/dist/activities/execute-cursor/capture-flow.js.map +1 -0
  31. package/dist/activities/execute-cursor/cas-observations.d.ts +96 -0
  32. package/dist/activities/execute-cursor/cas-observations.js +184 -0
  33. package/dist/activities/execute-cursor/cas-observations.js.map +1 -0
  34. package/dist/activities/execute-cursor/command-provenance.d.ts +62 -0
  35. package/dist/activities/execute-cursor/command-provenance.js +128 -0
  36. package/dist/activities/execute-cursor/command-provenance.js.map +1 -0
  37. package/dist/activities/execute-cursor/exact-apply.d.ts +110 -0
  38. package/dist/activities/execute-cursor/exact-apply.js +204 -0
  39. package/dist/activities/execute-cursor/exact-apply.js.map +1 -0
  40. package/dist/activities/execute-cursor/hook-script.d.ts +53 -24
  41. package/dist/activities/execute-cursor/hook-script.js +310 -47
  42. package/dist/activities/execute-cursor/hook-script.js.map +1 -1
  43. package/dist/activities/execute-cursor/index.d.ts +8 -1
  44. package/dist/activities/execute-cursor/index.js +500 -64
  45. package/dist/activities/execute-cursor/index.js.map +1 -1
  46. package/dist/activities/execute-cursor/message-translator.d.ts +258 -11
  47. package/dist/activities/execute-cursor/message-translator.js +836 -90
  48. package/dist/activities/execute-cursor/message-translator.js.map +1 -1
  49. package/dist/activities/execute-cursor/prompt-builder.d.ts +20 -23
  50. package/dist/activities/execute-cursor/prompt-builder.js +74 -15
  51. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  52. package/dist/activities/execute-cursor/workspace-setup.d.ts +17 -0
  53. package/dist/activities/execute-cursor/workspace-setup.js +212 -33
  54. package/dist/activities/execute-cursor/workspace-setup.js.map +1 -1
  55. package/dist/activities/execute-deep-agent/__test-utils__/gateway-substrate.d.ts +19 -0
  56. package/dist/activities/execute-deep-agent/__test-utils__/gateway-substrate.js +143 -0
  57. package/dist/activities/execute-deep-agent/__test-utils__/gateway-substrate.js.map +1 -0
  58. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.d.ts +88 -0
  59. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js +81 -0
  60. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js.map +1 -0
  61. package/dist/activities/execute-deep-agent/approval-file-change.d.ts +47 -0
  62. package/dist/activities/execute-deep-agent/approval-file-change.js +68 -0
  63. package/dist/activities/execute-deep-agent/approval-file-change.js.map +1 -0
  64. package/dist/activities/execute-deep-agent/attachment-injector.d.ts +8 -1
  65. package/dist/activities/execute-deep-agent/attachment-injector.js +7 -7
  66. package/dist/activities/execute-deep-agent/attachment-injector.js.map +1 -1
  67. package/dist/activities/execute-deep-agent/cas-capture-backend.d.ts +42 -0
  68. package/dist/activities/execute-deep-agent/cas-capture-backend.js +47 -0
  69. package/dist/activities/execute-deep-agent/cas-capture-backend.js.map +1 -0
  70. package/dist/activities/execute-deep-agent/cas-capture-observer.d.ts +79 -0
  71. package/dist/activities/execute-deep-agent/cas-capture-observer.js +112 -0
  72. package/dist/activities/execute-deep-agent/cas-capture-observer.js.map +1 -0
  73. package/dist/activities/execute-deep-agent/hitl.d.ts +16 -3
  74. package/dist/activities/execute-deep-agent/hitl.js +11 -3
  75. package/dist/activities/execute-deep-agent/hitl.js.map +1 -1
  76. package/dist/activities/execute-deep-agent/index.d.ts +2 -1
  77. package/dist/activities/execute-deep-agent/index.js +393 -33
  78. package/dist/activities/execute-deep-agent/index.js.map +1 -1
  79. package/dist/activities/execute-deep-agent/inline-publisher.d.ts +7 -1
  80. package/dist/activities/execute-deep-agent/inline-publisher.js +23 -2
  81. package/dist/activities/execute-deep-agent/inline-publisher.js.map +1 -1
  82. package/dist/activities/execute-deep-agent/setup.d.ts +53 -2
  83. package/dist/activities/execute-deep-agent/setup.js +149 -92
  84. package/dist/activities/execute-deep-agent/setup.js.map +1 -1
  85. package/dist/activities/execute-deep-agent/stamp-flowed-rows.d.ts +36 -0
  86. package/dist/activities/execute-deep-agent/stamp-flowed-rows.js +56 -0
  87. package/dist/activities/execute-deep-agent/stamp-flowed-rows.js.map +1 -0
  88. package/dist/activities/execute-deep-agent/status-builder-shared.d.ts +34 -1
  89. package/dist/activities/execute-deep-agent/status-builder-shared.js +26 -25
  90. package/dist/activities/execute-deep-agent/status-builder-shared.js.map +1 -1
  91. package/dist/activities/execute-deep-agent/status-builder.d.ts +17 -5
  92. package/dist/activities/execute-deep-agent/status-builder.js +44 -3
  93. package/dist/activities/execute-deep-agent/status-builder.js.map +1 -1
  94. package/dist/activities/execute-deep-agent/streaming-side-effects.js +2 -19
  95. package/dist/activities/execute-deep-agent/streaming-side-effects.js.map +1 -1
  96. package/dist/activities/execute-deep-agent/streaming.js +3 -15
  97. package/dist/activities/execute-deep-agent/streaming.js.map +1 -1
  98. package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +25 -7
  99. package/dist/activities/execute-deep-agent/subagent-transformer.js +23 -7
  100. package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
  101. package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +30 -3
  102. package/dist/activities/execute-deep-agent/subagent-wiring.js +29 -3
  103. package/dist/activities/execute-deep-agent/subagent-wiring.js.map +1 -1
  104. package/dist/activities/execute-deep-agent/v3-status-builder.js +32 -2
  105. package/dist/activities/execute-deep-agent/v3-status-builder.js.map +1 -1
  106. package/dist/claimcheck/payload-codec.js +9 -5
  107. package/dist/claimcheck/payload-codec.js.map +1 -1
  108. package/dist/client/stigmer-client.d.ts +2 -0
  109. package/dist/client/stigmer-client.js +2 -0
  110. package/dist/client/stigmer-client.js.map +1 -1
  111. package/dist/middleware/approval-gate.d.ts +85 -4
  112. package/dist/middleware/approval-gate.js +165 -38
  113. package/dist/middleware/approval-gate.js.map +1 -1
  114. package/dist/middleware/types.d.ts +2 -5
  115. package/dist/shared/activity-input.d.ts +43 -0
  116. package/dist/shared/activity-input.js +17 -0
  117. package/dist/shared/activity-input.js.map +1 -0
  118. package/dist/shared/approval-canonicalize.d.ts +19 -0
  119. package/dist/shared/approval-canonicalize.js +119 -0
  120. package/dist/shared/approval-canonicalize.js.map +1 -0
  121. package/dist/shared/approval-fingerprint.d.ts +106 -0
  122. package/dist/shared/approval-fingerprint.js +113 -0
  123. package/dist/shared/approval-fingerprint.js.map +1 -0
  124. package/dist/shared/approval-policy.d.ts +182 -12
  125. package/dist/shared/approval-policy.js +213 -27
  126. package/dist/shared/approval-policy.js.map +1 -1
  127. package/dist/shared/args-preview.d.ts +52 -0
  128. package/dist/shared/args-preview.js +93 -0
  129. package/dist/shared/args-preview.js.map +1 -0
  130. package/dist/shared/artifact-storage.d.ts +19 -1
  131. package/dist/shared/artifact-storage.js +48 -11
  132. package/dist/shared/artifact-storage.js.map +1 -1
  133. package/dist/shared/file-change.d.ts +44 -0
  134. package/dist/shared/file-change.js +57 -0
  135. package/dist/shared/file-change.js.map +1 -0
  136. package/dist/shared/file-tools.d.ts +107 -0
  137. package/dist/shared/file-tools.js +168 -0
  138. package/dist/shared/file-tools.js.map +1 -0
  139. package/dist/shared/filereview/capture.d.ts +202 -0
  140. package/dist/shared/filereview/capture.js +498 -0
  141. package/dist/shared/filereview/capture.js.map +1 -0
  142. package/dist/shared/filereview/cas-substrate.d.ts +190 -0
  143. package/dist/shared/filereview/cas-substrate.js +284 -0
  144. package/dist/shared/filereview/cas-substrate.js.map +1 -0
  145. package/dist/shared/filereview/digest.d.ts +40 -0
  146. package/dist/shared/filereview/digest.js +66 -0
  147. package/dist/shared/filereview/digest.js.map +1 -0
  148. package/dist/shared/filereview/events.d.ts +170 -0
  149. package/dist/shared/filereview/events.js +298 -0
  150. package/dist/shared/filereview/events.js.map +1 -0
  151. package/dist/shared/filereview/git-substrate.d.ts +175 -0
  152. package/dist/shared/filereview/git-substrate.js +439 -0
  153. package/dist/shared/filereview/git-substrate.js.map +1 -0
  154. package/dist/shared/filereview/index.d.ts +11 -0
  155. package/dist/shared/filereview/index.js +12 -0
  156. package/dist/shared/filereview/index.js.map +1 -0
  157. package/dist/shared/filereview/secret-paths.d.ts +63 -0
  158. package/dist/shared/filereview/secret-paths.js +105 -0
  159. package/dist/shared/filereview/secret-paths.js.map +1 -0
  160. package/dist/shared/fingerprint-secret.d.ts +26 -0
  161. package/dist/shared/fingerprint-secret.js +47 -0
  162. package/dist/shared/fingerprint-secret.js.map +1 -0
  163. package/dist/shared/model-client.d.ts +51 -0
  164. package/dist/shared/model-client.js +77 -0
  165. package/dist/shared/model-client.js.map +1 -0
  166. package/dist/shared/plan-artifact.js +0 -2
  167. package/dist/shared/plan-artifact.js.map +1 -1
  168. package/dist/shared/status-offload.d.ts +83 -9
  169. package/dist/shared/status-offload.js +399 -79
  170. package/dist/shared/status-offload.js.map +1 -1
  171. package/dist/shared/status.js +14 -1
  172. package/dist/shared/status.js.map +1 -1
  173. package/dist/shared/tool-kind.d.ts +19 -0
  174. package/dist/shared/tool-kind.js +13 -0
  175. package/dist/shared/tool-kind.js.map +1 -1
  176. package/dist/shared/tool-row.d.ts +88 -0
  177. package/dist/shared/tool-row.js +127 -0
  178. package/dist/shared/tool-row.js.map +1 -0
  179. package/dist/shared/workspace/platform-dir.d.ts +25 -0
  180. package/dist/shared/workspace/platform-dir.js +38 -2
  181. package/dist/shared/workspace/platform-dir.js.map +1 -1
  182. package/dist/workflows/call-agent-orchestrator.js +56 -7
  183. package/dist/workflows/call-agent-orchestrator.js.map +1 -1
  184. package/dist/workflows/connect-mcp-server.d.ts +50 -0
  185. package/dist/workflows/connect-mcp-server.js +136 -15
  186. package/dist/workflows/connect-mcp-server.js.map +1 -1
  187. package/dist/workflows/types.d.ts +8 -0
  188. package/package.json +2 -2
  189. package/src/__test-utils__/approval-contract/contract.ts +224 -0
  190. package/src/__test-utils__/approval-contract/types.ts +179 -0
  191. package/src/__test-utils__/fake-artifact-storage.ts +72 -0
  192. package/src/__tests__/approval-gateway-contract.test.ts +29 -0
  193. package/src/__tests__/claimcheck-codec.test.ts +16 -53
  194. package/src/__tests__/golden-e2e.test.ts +2 -0
  195. package/src/__tests__/runner-token-coordinator.test.ts +3 -3
  196. package/src/activities/__tests__/call-agent-status.test.ts +135 -0
  197. package/src/activities/__tests__/call-llm.test.ts +1 -1
  198. package/src/activities/__tests__/classify-tool-approvals.test.ts +208 -1
  199. package/src/activities/__tests__/discover-mcp-server.test.ts +30 -0
  200. package/src/activities/__tests__/workflow-event-activities.test.ts +2 -1
  201. package/src/activities/call-agent-status.ts +74 -4
  202. package/src/activities/call-llm.ts +18 -63
  203. package/src/activities/classify-tool-approvals.ts +101 -19
  204. package/src/activities/discover-mcp-server.ts +29 -1
  205. package/src/activities/execute-cursor/__test-utils__/cursor-hook-harness.ts +216 -0
  206. package/src/activities/execute-cursor/__test-utils__/gateway-substrate.ts +148 -0
  207. package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +41 -9
  208. package/src/activities/execute-cursor/__tests__/approval-state.test.ts +292 -0
  209. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +68 -1
  210. package/src/activities/execute-cursor/__tests__/capture-flow.test.ts +1005 -0
  211. package/src/activities/execute-cursor/__tests__/cas-observations.test.ts +187 -0
  212. package/src/activities/execute-cursor/__tests__/coarse-fingerprint.test.ts +97 -0
  213. package/src/activities/execute-cursor/__tests__/command-provenance.test.ts +240 -0
  214. package/src/activities/execute-cursor/__tests__/deny-gate-exact-apply.test.ts +203 -0
  215. package/src/activities/execute-cursor/__tests__/exact-apply.test.ts +375 -0
  216. package/src/activities/execute-cursor/__tests__/hitl-ledger.test.ts +1294 -24
  217. package/src/activities/execute-cursor/__tests__/hitl-resume-history.test.ts +446 -0
  218. package/src/activities/execute-cursor/__tests__/hook-script.test.ts +384 -110
  219. package/src/activities/execute-cursor/__tests__/message-translator.test.ts +171 -25
  220. package/src/activities/execute-cursor/__tests__/sequential-gate-resume.test.ts +189 -0
  221. package/src/activities/execute-cursor/__tests__/tool-result-image.test.ts +44 -23
  222. package/src/activities/execute-cursor/__tests__/workspace-setup.test.ts +190 -10
  223. package/src/activities/execute-cursor/approval-policy.ts +28 -159
  224. package/src/activities/execute-cursor/approval-state.ts +366 -18
  225. package/src/activities/execute-cursor/capture-flow.ts +323 -0
  226. package/src/activities/execute-cursor/cas-observations.ts +204 -0
  227. package/src/activities/execute-cursor/command-provenance.ts +168 -0
  228. package/src/activities/execute-cursor/exact-apply.ts +253 -0
  229. package/src/activities/execute-cursor/hook-script.ts +317 -51
  230. package/src/activities/execute-cursor/index.ts +575 -67
  231. package/src/activities/execute-cursor/message-translator.ts +963 -89
  232. package/src/activities/execute-cursor/prompt-builder.ts +80 -14
  233. package/src/activities/execute-cursor/workspace-setup.ts +257 -42
  234. package/src/activities/execute-deep-agent/__test-utils__/gateway-substrate.ts +180 -0
  235. package/src/activities/execute-deep-agent/__test-utils__/scripted-model.ts +134 -0
  236. package/src/activities/execute-deep-agent/__tests__/approval-file-change.test.ts +84 -0
  237. package/src/activities/execute-deep-agent/__tests__/attachment-injector.test.ts +11 -24
  238. package/src/activities/execute-deep-agent/__tests__/cas-capture-backend.test.ts +64 -0
  239. package/src/activities/execute-deep-agent/__tests__/cas-capture-observer.test.ts +163 -0
  240. package/src/activities/execute-deep-agent/__tests__/hitl-integration.test.ts +8 -5
  241. package/src/activities/execute-deep-agent/__tests__/hitl-resume-approve-all.test.ts +342 -0
  242. package/src/activities/execute-deep-agent/__tests__/hitl-resume-history.test.ts +284 -0
  243. package/src/activities/execute-deep-agent/__tests__/hitl.test.ts +14 -36
  244. package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +31 -13
  245. package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +349 -0
  246. package/src/activities/execute-deep-agent/__tests__/stamp-flowed-rows.test.ts +119 -0
  247. package/src/activities/execute-deep-agent/__tests__/status-builder.test.ts +91 -10
  248. package/src/activities/execute-deep-agent/__tests__/streaming-v3.test.ts +9 -9
  249. package/src/activities/execute-deep-agent/__tests__/subagent-approval-propagation.test.ts +160 -0
  250. package/src/activities/execute-deep-agent/__tests__/subagent-gitignored-capture.test.ts +213 -0
  251. package/src/activities/execute-deep-agent/__tests__/subagent-transformer.test.ts +3 -6
  252. package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +84 -1
  253. package/src/activities/execute-deep-agent/__tests__/v3-status-builder.test.ts +4 -1
  254. package/src/activities/execute-deep-agent/approval-file-change.ts +80 -0
  255. package/src/activities/execute-deep-agent/attachment-injector.ts +20 -11
  256. package/src/activities/execute-deep-agent/cas-capture-backend.ts +66 -0
  257. package/src/activities/execute-deep-agent/cas-capture-observer.ts +125 -0
  258. package/src/activities/execute-deep-agent/hitl.ts +23 -7
  259. package/src/activities/execute-deep-agent/index.ts +463 -40
  260. package/src/activities/execute-deep-agent/inline-publisher.ts +27 -4
  261. package/src/activities/execute-deep-agent/setup.ts +223 -125
  262. package/src/activities/execute-deep-agent/stamp-flowed-rows.ts +64 -0
  263. package/src/activities/execute-deep-agent/status-builder-shared.ts +62 -23
  264. package/src/activities/execute-deep-agent/status-builder.ts +63 -8
  265. package/src/activities/execute-deep-agent/streaming-side-effects.ts +2 -16
  266. package/src/activities/execute-deep-agent/streaming.ts +3 -13
  267. package/src/activities/execute-deep-agent/subagent-transformer.ts +53 -13
  268. package/src/activities/execute-deep-agent/subagent-wiring.ts +50 -3
  269. package/src/activities/execute-deep-agent/v3-status-builder.ts +36 -2
  270. package/src/claimcheck/payload-codec.ts +8 -8
  271. package/src/client/stigmer-client.ts +9 -1
  272. package/src/middleware/__tests__/approval-gate.test.ts +488 -4
  273. package/src/middleware/approval-gate.ts +247 -38
  274. package/src/middleware/types.ts +5 -5
  275. package/src/shared/__tests__/activity-input.test.ts +78 -0
  276. package/src/shared/__tests__/approval-canonicalize.test.ts +106 -0
  277. package/src/shared/__tests__/approval-fingerprint.test.ts +115 -0
  278. package/src/shared/__tests__/approval-policy.test.ts +274 -40
  279. package/src/shared/__tests__/args-preview.test.ts +78 -0
  280. package/src/shared/__tests__/artifact-storage-extended.test.ts +62 -10
  281. package/src/shared/__tests__/artifact-storage.test.ts +123 -11
  282. package/src/shared/__tests__/file-change.test.ts +85 -0
  283. package/src/shared/__tests__/file-tools.test.ts +90 -0
  284. package/src/shared/__tests__/fingerprint-secret.test.ts +51 -0
  285. package/src/shared/__tests__/lease-scope-corpus.test.ts +56 -0
  286. package/src/shared/__tests__/model-client.test.ts +162 -0
  287. package/src/shared/__tests__/plan-artifact.test.ts +11 -26
  288. package/src/shared/__tests__/policy-source-corpus.test.ts +58 -0
  289. package/src/shared/__tests__/status-offload.test.ts +573 -16
  290. package/src/shared/__tests__/status.test.ts +4 -5
  291. package/src/shared/__tests__/tool-kind.test.ts +24 -1
  292. package/src/shared/__tests__/tool-row.test.ts +221 -0
  293. package/src/shared/activity-input.ts +57 -0
  294. package/src/shared/approval-canonicalize.ts +159 -0
  295. package/src/shared/approval-fingerprint.ts +148 -0
  296. package/src/shared/approval-policy.ts +303 -27
  297. package/src/shared/args-preview.ts +98 -0
  298. package/src/shared/artifact-storage.ts +62 -11
  299. package/src/shared/checkpointer/__tests__/http-saver.test.ts +1 -2
  300. package/src/shared/file-change.ts +64 -0
  301. package/src/shared/file-tools.ts +169 -0
  302. package/src/shared/filereview/__tests__/capture.test.ts +856 -0
  303. package/src/shared/filereview/__tests__/cas-substrate.test.ts +404 -0
  304. package/src/shared/filereview/__tests__/digest.test.ts +100 -0
  305. package/src/shared/filereview/__tests__/events.test.ts +245 -0
  306. package/src/shared/filereview/__tests__/git-substrate.test.ts +362 -0
  307. package/src/shared/filereview/__tests__/proxy-reconcile.test.ts +286 -0
  308. package/src/shared/filereview/__tests__/secret-paths.test.ts +121 -0
  309. package/src/shared/filereview/capture.ts +727 -0
  310. package/src/shared/filereview/cas-substrate.ts +401 -0
  311. package/src/shared/filereview/digest.ts +83 -0
  312. package/src/shared/filereview/events.ts +449 -0
  313. package/src/shared/filereview/git-substrate.ts +555 -0
  314. package/src/shared/filereview/index.ts +60 -0
  315. package/src/shared/filereview/secret-paths.ts +121 -0
  316. package/src/shared/fingerprint-secret.ts +53 -0
  317. package/src/shared/model-client.ts +122 -0
  318. package/src/shared/plan-artifact.ts +0 -2
  319. package/src/shared/status-offload.ts +433 -77
  320. package/src/shared/status.ts +13 -0
  321. package/src/shared/tool-kind.ts +33 -0
  322. package/src/shared/tool-row.ts +135 -0
  323. package/src/shared/workspace/platform-dir.ts +41 -2
  324. package/src/workflow-engine/__tests__/golden-execution.test.ts +35 -18
  325. package/src/workflow-engine/__tests__/tasks/try.test.ts +1 -1
  326. package/src/workflows/__tests__/connect-mcp-server.test.ts +304 -29
  327. package/src/workflows/call-agent-orchestrator.ts +53 -6
  328. package/src/workflows/connect-mcp-server.ts +179 -24
  329. package/src/workflows/types.ts +8 -0
@@ -0,0 +1,170 @@
1
+ /**
2
+ * The runner's file-review event producer: maps a harness-agnostic capture into
3
+ * the proto {@code CapturedFileChange} + {@code FileReviewEvent} ledger entries
4
+ * the server folds (append-only, by event_id) into the server-owned stream.
5
+ *
6
+ * This is the runner half of the apply-then-review subsystem. It is intentionally
7
+ * harness-agnostic — it takes per-file before/after content and a kind, not a
8
+ * git-specific shape — so the Cursor (git substrate) and deep-agent (mutation
9
+ * buffer) harnesses author IDENTICAL ledger entries through one seam. Event ids
10
+ * are deterministic ({@link eventId}) so a re-sent heartbeat or a Temporal retry
11
+ * never duplicates an event.
12
+ */
13
+ import type { AgentExecutionStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
14
+ import type { CapturedFileChange, FileReviewEvent, SnapshotRef, TurnCommandProvenance } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/filereview_pb";
15
+ import { DiffCompleteness, FileCaptureClass, FileChangeKind, FileReviewBlockReason, FileReviewEventType, FileReviewFailureKind } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
16
+ /**
17
+ * The deterministic idempotency key for a file-review event:
18
+ * `changeSetId:scopeId:eventTypeName`. Capture/reconcile/failure events are
19
+ * change-set-scoped (scopeId == changeSetId); the per-file decision scope is the
20
+ * server's concern. Identical to the Go/Java EventID.
21
+ */
22
+ export declare function eventId(changeSetId: string, scopeId: string, type: FileReviewEventType): string;
23
+ /**
24
+ * One side (before/after) of a captured file's content, in one of three shapes:
25
+ *
26
+ * - `inline` — the raw text bytes, carried on the wire (the git substrate reads
27
+ * them from the tree for text files). A plain string is accepted as shorthand.
28
+ * - `ref` — a reference to an already-stored, content-addressed blob (the CAS
29
+ * substrate offloads ignored / non-git bodies to artifact storage and carries
30
+ * the ref, so the body is never stored twice).
31
+ * - `binary` — a git-tracked binary side: NO body is carried (a binary has no
32
+ * reviewable text diff, and reconcile sources its bytes byte-exact from the
33
+ * git ref, never from the wire), only the byte-true content address. This is
34
+ * what keeps the enforcement digest honest for binaries — hashing a UTF-8
35
+ * decode of binary bytes would be lossy.
36
+ */
37
+ export type CapturedContent = {
38
+ readonly kind: "inline";
39
+ readonly text: string;
40
+ /**
41
+ * Byte-true SHA-256 of the RAW bytes, when the producer computed it at the
42
+ * source (the git substrate does). Preferred over hashing `text`, which for
43
+ * a non-UTF-8 blob (e.g. latin-1 with no NUL) would hash a lossy decode.
44
+ * Absent for the plain-string shorthand, where `text` IS the exact content.
45
+ */
46
+ readonly sha256?: string;
47
+ } | {
48
+ readonly kind: "ref";
49
+ /** Content address of the referenced blob (the enforcement digest). */
50
+ readonly sha256: string;
51
+ readonly storageKey: string;
52
+ readonly sizeBytes: number;
53
+ readonly isBinary: boolean;
54
+ readonly mimeType?: string;
55
+ } | {
56
+ readonly kind: "binary";
57
+ /** Byte-true SHA-256 of the raw bytes (the enforcement digest). */
58
+ readonly sha256: string;
59
+ };
60
+ /** A single captured file delta, harness-agnostic (no git/CAS specifics). */
61
+ export interface CapturedChangeInput {
62
+ /** Stable id of this file change within its set (correlation key, never a hash). */
63
+ readonly id: string;
64
+ /** Path before the change (workspace-root-relative). Empty for ADD. */
65
+ readonly pathBefore: string;
66
+ /** Path after the change. Empty for DELETE; differs from pathBefore for RENAME. */
67
+ readonly pathAfter: string;
68
+ readonly kind: FileChangeKind;
69
+ /** Which substrate captured this file (git-tracked, ignored, CAS, ...). */
70
+ readonly captureClass: FileCaptureClass;
71
+ /** Pre-edit content (inline string, or a blob ref). Omit for ADD. */
72
+ readonly before?: string | CapturedContent;
73
+ /** Post-edit content (inline string, or a blob ref). Omit for DELETE. */
74
+ readonly after?: string | CapturedContent;
75
+ /**
76
+ * False when this file's diff could not be captured completely (too large to
77
+ * persist inline before CAS exists, truncated, or binary-only). A change set
78
+ * with any incomplete file cannot be approved as complete.
79
+ */
80
+ readonly diffComplete?: boolean;
81
+ /**
82
+ * The honest cause the diff is not fully reviewable, set only alongside
83
+ * `diffComplete === false` (defaults to UNSPECIFIED). Informational provenance
84
+ * for the review UI — never an enforcement input and never folded into the
85
+ * digests. Binary is conveyed by FileContent.is_binary, so binary files leave
86
+ * this UNSPECIFIED. See {@link FileReviewBlockReason}.
87
+ */
88
+ readonly blockedReason?: FileReviewBlockReason;
89
+ }
90
+ /**
91
+ * The enforcement digest of one content side. Inline text is hashed as UTF-8
92
+ * bytes; a `ref`/`binary` side already carries its byte-true content address, so
93
+ * it is reused verbatim. This single function is the sole sha authority — used
94
+ * both at capture (in {@link buildCapturedFileChange}) and at the resume-time
95
+ * reconcile check — so the two are consistent by construction across substrates.
96
+ */
97
+ export declare function contentSha256(content: CapturedContent): string;
98
+ /**
99
+ * Build a proto {@link CapturedFileChange} from harness-agnostic input,
100
+ * computing the enforcement digests (`before_sha256`, `after_sha256`,
101
+ * `file_digest`) over the captured bytes. Content may be inline (git) or a blob
102
+ * ref (CAS) — the digests are identical either way, so the aggregate digest and
103
+ * the reconcile enforcement compose across both substrates.
104
+ */
105
+ export declare function buildCapturedFileChange(input: CapturedChangeInput): CapturedFileChange;
106
+ /** Coordinates a change set's lifecycle so every event carries one identity. */
107
+ export interface ChangeSetContext {
108
+ readonly changeSetId: string;
109
+ readonly turnId: string;
110
+ /** "cursor" | "deep-agent". */
111
+ readonly harnessId: string;
112
+ /** ISO 8601 timestamp authored onto each event. */
113
+ readonly timestamp: string;
114
+ }
115
+ /**
116
+ * The BASELINE_CAPTURED event — the first event of a change set's lifecycle,
117
+ * authored at turn start so the projection can materialize the set before any
118
+ * candidate exists.
119
+ */
120
+ export declare function buildBaselineCapturedEvent(ctx: ChangeSetContext, baselineSnapshot: SnapshotRef | undefined): FileReviewEvent;
121
+ /**
122
+ * Derive a change set's {@link DiffCompleteness} rollup from its per-file
123
+ * signals — the single source of the three-way rule, shared by the turn-boundary
124
+ * capture ({@link buildCandidateCapturedEvent}) and the size backstop
125
+ * (status-offload), so the value can never be computed two ways:
126
+ *
127
+ * - every file complete → `COMPLETE`
128
+ * - else the ONLY incompleteness is binary (every incomplete file has a binary
129
+ * side) → `BINARY_SUMMARY_ONLY` — keepable in one acknowledged action, its
130
+ * exact bytes reconcile from the git ref / CAS blob
131
+ * - else (≥1 non-binary incomplete: secret-withheld / size-elided /
132
+ * uncapturable — no keepable bytes) → `PARTIAL_BLOCKED`
133
+ *
134
+ * Binary is proven by `FileContent.is_binary` on either side (DD-15 D2), never
135
+ * by the block reason. This mirrors the backend gate's `isBinaryChange`, so the
136
+ * runner's rollup and the gate's per-file re-derivation agree by construction.
137
+ */
138
+ export declare function deriveDiffCompleteness(changes: readonly CapturedFileChange[]): DiffCompleteness;
139
+ /**
140
+ * The CANDIDATE_CAPTURED event — authored at the turn boundary, carrying the
141
+ * authoritative per-file diff and the aggregate digest. `diff_completeness` is
142
+ * the {@link deriveDiffCompleteness} rollup over the changes.
143
+ *
144
+ * `commandProvenance` (optional, DD-28) is the harness's approved-command turn
145
+ * facts: when present, the backend verifies the cited consent rows against its
146
+ * server-authored approval record and — on success — auto-keeps the set with a
147
+ * policy-origin decision instead of arming the review gate. Never folded into
148
+ * the aggregate digest (provenance, not content).
149
+ */
150
+ export declare function buildCandidateCapturedEvent(ctx: ChangeSetContext, candidateSnapshot: SnapshotRef | undefined, changes: readonly CapturedFileChange[], commandProvenance?: TurnCommandProvenance): FileReviewEvent;
151
+ /** The RECONCILED event — authored after decisions are applied and verified. */
152
+ export declare function buildReconciledEvent(ctx: ChangeSetContext, approvedSnapshot: SnapshotRef | undefined): FileReviewEvent;
153
+ /** A terminal FAILED event in the file-review lifecycle (audit + resume). */
154
+ export declare function buildFailedEvent(ctx: ChangeSetContext, kind: FileReviewFailureKind, detail: string): FileReviewEvent;
155
+ /**
156
+ * Whether a CANDIDATE_CAPTURED event exists for `changeSetId` on the status's
157
+ * file_review stream — i.e. this turn actually produced a reviewable change
158
+ * set. The capture seam authors no event for a no-op turn (an edit fully
159
+ * reverted before the boundary), so this is the single signal both harnesses
160
+ * gate on before opening a review or stamping transcript rows: a row must
161
+ * never reference a change set that does not exist.
162
+ */
163
+ export declare function hasCandidateCaptured(status: AgentExecutionStatus, changeSetId: string): boolean;
164
+ /**
165
+ * Append the runner-authored events onto the status's file_review stream
166
+ * (seeding it if absent), idempotently by event_id. The server re-applies the
167
+ * same append-only/by-id discipline on receipt, so re-sending across throttled
168
+ * persists is safe; this keeps the in-runner status consistent between persists.
169
+ */
170
+ export declare function appendFileReviewEvents(status: AgentExecutionStatus, executionId: string, events: readonly FileReviewEvent[]): void;
@@ -0,0 +1,298 @@
1
+ /**
2
+ * The runner's file-review event producer: maps a harness-agnostic capture into
3
+ * the proto {@code CapturedFileChange} + {@code FileReviewEvent} ledger entries
4
+ * the server folds (append-only, by event_id) into the server-owned stream.
5
+ *
6
+ * This is the runner half of the apply-then-review subsystem. It is intentionally
7
+ * harness-agnostic — it takes per-file before/after content and a kind, not a
8
+ * git-specific shape — so the Cursor (git substrate) and deep-agent (mutation
9
+ * buffer) harnesses author IDENTICAL ledger entries through one seam. Event ids
10
+ * are deterministic ({@link eventId}) so a re-sent heartbeat or a Temporal retry
11
+ * never duplicates an event.
12
+ */
13
+ import { create } from "@bufbuild/protobuf";
14
+ import { CapturedFileChangeSchema, FileReviewBaselineCapturedSchema, FileReviewCandidateCapturedSchema, FileReviewEventSchema, FileReviewEventStreamSchema, FileReviewFailureSchema, FileReviewReconciledSchema, } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/filereview_pb";
15
+ import { FileContentSchema, ToolCallOutputRefSchema, } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
16
+ import { DiffCompleteness, FileReviewBlockReason, FileReviewEventType, } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
17
+ import { aggregateDigest, fileDigest, sha256Bytes } from "./digest.js";
18
+ import { looksBinary } from "../file-change.js";
19
+ // The runner is the author of capture/reconcile/failure events. "runner" (not
20
+ // the generic "system") matches the cross-edition corpus fixtures and the
21
+ // proto's actor convention ("runner" for capture/reconcile, "user" for
22
+ // decisions). The projection ignores actor, but keeping it canonical keeps the
23
+ // ledger self-describing and the dual-edition corpus honest.
24
+ const ACTOR_RUNNER = "runner";
25
+ /**
26
+ * The proto enum value NAME for a {@link FileReviewEventType}, e.g.
27
+ * `FILE_REVIEW_EVENT_TYPE_BASELINE_CAPTURED`. {@link eventId} hashes this name so
28
+ * the runner's ids are byte-identical to the Go `author.EventID` / Java
29
+ * `FileReviewStreamAuthor.eventId` (which use the proto name).
30
+ */
31
+ const FILE_REVIEW_EVENT_TYPE_NAME = {
32
+ [FileReviewEventType.UNSPECIFIED]: "FILE_REVIEW_EVENT_TYPE_UNSPECIFIED",
33
+ [FileReviewEventType.BASELINE_CAPTURED]: "FILE_REVIEW_EVENT_TYPE_BASELINE_CAPTURED",
34
+ [FileReviewEventType.CANDIDATE_CAPTURED]: "FILE_REVIEW_EVENT_TYPE_CANDIDATE_CAPTURED",
35
+ [FileReviewEventType.FILE_DECIDED]: "FILE_REVIEW_EVENT_TYPE_FILE_DECIDED",
36
+ [FileReviewEventType.RECONCILED]: "FILE_REVIEW_EVENT_TYPE_RECONCILED",
37
+ [FileReviewEventType.FAILED]: "FILE_REVIEW_EVENT_TYPE_FAILED",
38
+ };
39
+ /**
40
+ * The deterministic idempotency key for a file-review event:
41
+ * `changeSetId:scopeId:eventTypeName`. Capture/reconcile/failure events are
42
+ * change-set-scoped (scopeId == changeSetId); the per-file decision scope is the
43
+ * server's concern. Identical to the Go/Java EventID.
44
+ */
45
+ export function eventId(changeSetId, scopeId, type) {
46
+ return `${changeSetId}:${scopeId}:${FILE_REVIEW_EVENT_TYPE_NAME[type]}`;
47
+ }
48
+ /** Normalize the string-shorthand to a {@link CapturedContent}. */
49
+ function normalizeContent(v) {
50
+ if (v === undefined)
51
+ return undefined;
52
+ return typeof v === "string" ? { kind: "inline", text: v } : v;
53
+ }
54
+ /**
55
+ * The enforcement digest of one content side. Inline text is hashed as UTF-8
56
+ * bytes; a `ref`/`binary` side already carries its byte-true content address, so
57
+ * it is reused verbatim. This single function is the sole sha authority — used
58
+ * both at capture (in {@link buildCapturedFileChange}) and at the resume-time
59
+ * reconcile check — so the two are consistent by construction across substrates.
60
+ */
61
+ export function contentSha256(content) {
62
+ switch (content.kind) {
63
+ case "inline":
64
+ return content.sha256 ?? sha256Bytes(Buffer.from(content.text, "utf8"));
65
+ case "ref":
66
+ case "binary":
67
+ return content.sha256;
68
+ }
69
+ }
70
+ /** Build the proto {@link FileContent} for one content side (inline, ref, or binary). */
71
+ function toFileContent(content) {
72
+ if (content.kind === "inline") {
73
+ return create(FileContentSchema, {
74
+ body: { case: "inline", value: content.text },
75
+ isBinary: looksBinary(content.text),
76
+ });
77
+ }
78
+ // A git-tracked binary carries no body: its bytes reconcile from the git ref,
79
+ // and a text diff of binary content is meaningless. Consumers key off the
80
+ // is_binary flag (the SDK renders "binary file changed"; the backend gates
81
+ // approval on it), never a body.
82
+ if (content.kind === "binary") {
83
+ return create(FileContentSchema, { isBinary: true });
84
+ }
85
+ return create(FileContentSchema, {
86
+ body: {
87
+ case: "ref",
88
+ value: create(ToolCallOutputRefSchema, {
89
+ storageKey: content.storageKey,
90
+ sizeBytes: BigInt(content.sizeBytes),
91
+ contentHash: content.sha256,
92
+ mimeType: content.mimeType ?? "application/octet-stream",
93
+ isImage: false,
94
+ truncatedPreview: "",
95
+ }),
96
+ },
97
+ isBinary: content.isBinary,
98
+ });
99
+ }
100
+ /**
101
+ * Build a proto {@link CapturedFileChange} from harness-agnostic input,
102
+ * computing the enforcement digests (`before_sha256`, `after_sha256`,
103
+ * `file_digest`) over the captured bytes. Content may be inline (git) or a blob
104
+ * ref (CAS) — the digests are identical either way, so the aggregate digest and
105
+ * the reconcile enforcement compose across both substrates.
106
+ */
107
+ export function buildCapturedFileChange(input) {
108
+ const before = normalizeContent(input.before);
109
+ const after = normalizeContent(input.after);
110
+ const beforeSha256 = before ? contentSha256(before) : "";
111
+ const afterSha256 = after ? contentSha256(after) : "";
112
+ const fc = create(CapturedFileChangeSchema, {
113
+ id: input.id,
114
+ pathBefore: input.pathBefore,
115
+ pathAfter: input.pathAfter,
116
+ kind: input.kind,
117
+ captureClass: input.captureClass,
118
+ beforeSha256,
119
+ afterSha256,
120
+ diffComplete: input.diffComplete ?? true,
121
+ blockedReason: input.blockedReason ?? FileReviewBlockReason.UNSPECIFIED,
122
+ fileDigest: fileDigest({
123
+ pathBefore: input.pathBefore,
124
+ pathAfter: input.pathAfter,
125
+ kind: input.kind,
126
+ beforeSha256,
127
+ afterSha256,
128
+ }),
129
+ });
130
+ if (before) {
131
+ fc.before = toFileContent(before);
132
+ }
133
+ if (after) {
134
+ fc.after = toFileContent(after);
135
+ }
136
+ return fc;
137
+ }
138
+ /**
139
+ * The BASELINE_CAPTURED event — the first event of a change set's lifecycle,
140
+ * authored at turn start so the projection can materialize the set before any
141
+ * candidate exists.
142
+ */
143
+ export function buildBaselineCapturedEvent(ctx, baselineSnapshot) {
144
+ return create(FileReviewEventSchema, {
145
+ eventId: eventId(ctx.changeSetId, ctx.changeSetId, FileReviewEventType.BASELINE_CAPTURED),
146
+ changeSetId: ctx.changeSetId,
147
+ eventType: FileReviewEventType.BASELINE_CAPTURED,
148
+ timestamp: ctx.timestamp,
149
+ actor: ACTOR_RUNNER,
150
+ payload: {
151
+ case: "baselineCaptured",
152
+ value: create(FileReviewBaselineCapturedSchema, {
153
+ changeSetId: ctx.changeSetId,
154
+ turnId: ctx.turnId,
155
+ harnessId: ctx.harnessId,
156
+ ...(baselineSnapshot ? { baselineSnapshot } : {}),
157
+ }),
158
+ },
159
+ });
160
+ }
161
+ /**
162
+ * Derive a change set's {@link DiffCompleteness} rollup from its per-file
163
+ * signals — the single source of the three-way rule, shared by the turn-boundary
164
+ * capture ({@link buildCandidateCapturedEvent}) and the size backstop
165
+ * (status-offload), so the value can never be computed two ways:
166
+ *
167
+ * - every file complete → `COMPLETE`
168
+ * - else the ONLY incompleteness is binary (every incomplete file has a binary
169
+ * side) → `BINARY_SUMMARY_ONLY` — keepable in one acknowledged action, its
170
+ * exact bytes reconcile from the git ref / CAS blob
171
+ * - else (≥1 non-binary incomplete: secret-withheld / size-elided /
172
+ * uncapturable — no keepable bytes) → `PARTIAL_BLOCKED`
173
+ *
174
+ * Binary is proven by `FileContent.is_binary` on either side (DD-15 D2), never
175
+ * by the block reason. This mirrors the backend gate's `isBinaryChange`, so the
176
+ * runner's rollup and the gate's per-file re-derivation agree by construction.
177
+ */
178
+ export function deriveDiffCompleteness(changes) {
179
+ let sawIncomplete = false;
180
+ for (const c of changes) {
181
+ if (c.diffComplete)
182
+ continue;
183
+ sawIncomplete = true;
184
+ if (!(c.before?.isBinary || c.after?.isBinary)) {
185
+ // A non-binary incompleteness has no keepable bytes — it blocks the set
186
+ // outright, regardless of any binaries alongside it.
187
+ return DiffCompleteness.PARTIAL_BLOCKED;
188
+ }
189
+ }
190
+ if (!sawIncomplete)
191
+ return DiffCompleteness.COMPLETE;
192
+ return DiffCompleteness.BINARY_SUMMARY_ONLY;
193
+ }
194
+ /**
195
+ * The CANDIDATE_CAPTURED event — authored at the turn boundary, carrying the
196
+ * authoritative per-file diff and the aggregate digest. `diff_completeness` is
197
+ * the {@link deriveDiffCompleteness} rollup over the changes.
198
+ *
199
+ * `commandProvenance` (optional, DD-28) is the harness's approved-command turn
200
+ * facts: when present, the backend verifies the cited consent rows against its
201
+ * server-authored approval record and — on success — auto-keeps the set with a
202
+ * policy-origin decision instead of arming the review gate. Never folded into
203
+ * the aggregate digest (provenance, not content).
204
+ */
205
+ export function buildCandidateCapturedEvent(ctx, candidateSnapshot, changes, commandProvenance) {
206
+ return create(FileReviewEventSchema, {
207
+ eventId: eventId(ctx.changeSetId, ctx.changeSetId, FileReviewEventType.CANDIDATE_CAPTURED),
208
+ changeSetId: ctx.changeSetId,
209
+ eventType: FileReviewEventType.CANDIDATE_CAPTURED,
210
+ timestamp: ctx.timestamp,
211
+ actor: ACTOR_RUNNER,
212
+ payload: {
213
+ case: "candidateCaptured",
214
+ value: create(FileReviewCandidateCapturedSchema, {
215
+ changeSetId: ctx.changeSetId,
216
+ ...(candidateSnapshot ? { candidateSnapshot } : {}),
217
+ changes: [...changes],
218
+ aggregateDigest: aggregateDigest(changes.map((c) => ({
219
+ pathBefore: c.pathBefore,
220
+ pathAfter: c.pathAfter,
221
+ kind: c.kind,
222
+ beforeSha256: c.beforeSha256,
223
+ afterSha256: c.afterSha256,
224
+ }))),
225
+ diffCompleteness: deriveDiffCompleteness(changes),
226
+ ...(commandProvenance ? { commandProvenance } : {}),
227
+ }),
228
+ },
229
+ });
230
+ }
231
+ /** The RECONCILED event — authored after decisions are applied and verified. */
232
+ export function buildReconciledEvent(ctx, approvedSnapshot) {
233
+ return create(FileReviewEventSchema, {
234
+ eventId: eventId(ctx.changeSetId, ctx.changeSetId, FileReviewEventType.RECONCILED),
235
+ changeSetId: ctx.changeSetId,
236
+ eventType: FileReviewEventType.RECONCILED,
237
+ timestamp: ctx.timestamp,
238
+ actor: ACTOR_RUNNER,
239
+ payload: {
240
+ case: "reconciled",
241
+ value: create(FileReviewReconciledSchema, {
242
+ changeSetId: ctx.changeSetId,
243
+ ...(approvedSnapshot ? { approvedSnapshot } : {}),
244
+ }),
245
+ },
246
+ });
247
+ }
248
+ /** A terminal FAILED event in the file-review lifecycle (audit + resume). */
249
+ export function buildFailedEvent(ctx, kind, detail) {
250
+ return create(FileReviewEventSchema, {
251
+ eventId: eventId(ctx.changeSetId, ctx.changeSetId, FileReviewEventType.FAILED),
252
+ changeSetId: ctx.changeSetId,
253
+ eventType: FileReviewEventType.FAILED,
254
+ timestamp: ctx.timestamp,
255
+ actor: ACTOR_RUNNER,
256
+ payload: {
257
+ case: "failed",
258
+ value: create(FileReviewFailureSchema, { changeSetId: ctx.changeSetId, kind, detail }),
259
+ },
260
+ });
261
+ }
262
+ /**
263
+ * Whether a CANDIDATE_CAPTURED event exists for `changeSetId` on the status's
264
+ * file_review stream — i.e. this turn actually produced a reviewable change
265
+ * set. The capture seam authors no event for a no-op turn (an edit fully
266
+ * reverted before the boundary), so this is the single signal both harnesses
267
+ * gate on before opening a review or stamping transcript rows: a row must
268
+ * never reference a change set that does not exist.
269
+ */
270
+ export function hasCandidateCaptured(status, changeSetId) {
271
+ return (status.fileReviewEventStream?.events ?? []).some((e) => e.changeSetId === changeSetId &&
272
+ e.eventType === FileReviewEventType.CANDIDATE_CAPTURED);
273
+ }
274
+ /**
275
+ * Append the runner-authored events onto the status's file_review stream
276
+ * (seeding it if absent), idempotently by event_id. The server re-applies the
277
+ * same append-only/by-id discipline on receipt, so re-sending across throttled
278
+ * persists is safe; this keeps the in-runner status consistent between persists.
279
+ */
280
+ export function appendFileReviewEvents(status, executionId, events) {
281
+ if (events.length === 0)
282
+ return;
283
+ if (!status.fileReviewEventStream) {
284
+ status.fileReviewEventStream = create(FileReviewEventStreamSchema, {
285
+ executionId,
286
+ events: [],
287
+ });
288
+ }
289
+ const stream = status.fileReviewEventStream;
290
+ const seen = new Set(stream.events.map((e) => e.eventId));
291
+ for (const ev of events) {
292
+ if (seen.has(ev.eventId))
293
+ continue;
294
+ seen.add(ev.eventId);
295
+ stream.events.push(ev);
296
+ }
297
+ }
298
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/shared/filereview/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Git snapshot/restore substrate for the apply-then-review HITL "capture mode".
3
+ *
4
+ * THE MODEL
5
+ * ---------
6
+ * Edits are applied to the working tree and reviewed AFTER the fact; rejecting a
7
+ * file snaps it back exactly. We use git as a NO-COMMIT snapshot/restore
8
+ * substrate at the turn boundary:
9
+ *
10
+ * 1. snapshotBaseline() at turn start — record the exact pre-turn working tree
11
+ * and pin it behind a ref so it survives a multi-day approval wait.
12
+ * 2. The agent edits files freely (the gate allows git-tracked write/edit/delete).
13
+ * 3. captureChangeSet() at turn end — diff the post-turn tree against the
14
+ * baseline into a per-file change set, and pin the post-turn ("after") tree
15
+ * behind a ref. The working tree is LEFT in its "after" state: the user
16
+ * reviews the real, applied change and the workspace browser shows it.
17
+ * 4. On resume, reconcile the working tree to the per-file decisions, sourced
18
+ * ENTIRELY from the two pinned refs (not the live tree, not the persisted
19
+ * bodies — the refs are the single source of truth):
20
+ * - approved -> applyApprovedPaths() ensures the "after" bytes.
21
+ * - rejected/undecided -> restoreToBaseline() snaps the file back to its
22
+ * exact pre-turn bytes.
23
+ * This is symmetric and idempotent: it converges to the correct end state
24
+ * regardless of the tree's current contents, so a Temporal retry or a tree
25
+ * reset is harmless.
26
+ * 5. dropCaptureRefs() releases the pinned objects.
27
+ *
28
+ * HARNESS-AGNOSTIC
29
+ * ----------------
30
+ * This is pure git plumbing keyed by `executionId`. It carries no Cursor- or
31
+ * deep-agent-specific knowledge: the runner-owned files a harness writes into the
32
+ * workspace (e.g. the Cursor gate's `.cursor/hooks.json`) are passed in as
33
+ * `excludePaths` so they never pollute the captured diff, rather than being
34
+ * hard-coded here. Both harnesses author IDENTICAL ledger entries through the
35
+ * shared producer (events.ts) on top of this substrate. A future CAS substrate
36
+ * (for ignored / non-git paths) sits beside this module.
37
+ *
38
+ * NOTHING IS PERMANENT UNTIL APPROVAL
39
+ * -----------------------------------
40
+ * Edits are visible during review, but nothing is committed and the next turn is
41
+ * blocked until the user decides; a reject snaps the file back byte-for-byte from
42
+ * the baseline ref. Shell/MCP and gitignored writes/deletes are NOT reversible by
43
+ * this substrate, so they stay on the approve-before-run gate (see each harness's
44
+ * gate: the Cursor hook and the deep-agent approval-gate middleware).
45
+ *
46
+ * WHY GIT, NO COMMITS
47
+ * -------------------
48
+ * Git is used ONLY as an exact, reversible capture/restore mechanism. We never
49
+ * move HEAD, never touch a branch, never push. Approved work stays uncommitted;
50
+ * a harness's own writeback path (if any) commits the reconciled tree afterwards.
51
+ *
52
+ * HARD INVARIANTS
53
+ * ---------------
54
+ * - NEVER `git clean -x`/`-a` or `git stash -a`: the git-excluded `.stigmer/`
55
+ * directory holds SDK resume state and MUST survive. `git clean -fd` (no `-x`)
56
+ * leaves ignored paths alone, so `.stigmer`/`lost+found` are safe.
57
+ * - Runner-owned files written into the workspace are EXCLUDED (via `excludePaths`)
58
+ * from both the baseline and the after tree, so they never pollute the captured
59
+ * diff regardless of gate-teardown ordering.
60
+ * - All staging uses a TEMP index (GIT_INDEX_FILE) so the repo's real index is
61
+ * never disturbed.
62
+ */
63
+ import { FileChangeType } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
64
+ import type { CapturedContent } from "./events.js";
65
+ /**
66
+ * Refs that pin the per-execution baseline and after trees against GC. Exported
67
+ * so the file-review producer can stamp them onto the ledger's SnapshotRef
68
+ * (GitTreeRef.ref) without re-deriving the format. Keyed by executionId only:
69
+ * the unified gate guarantees at most one un-reconciled change set per execution
70
+ * at a time, and the reconcile drops these refs before the next turn re-pins.
71
+ */
72
+ export declare function baselineRef(executionId: string): string;
73
+ export declare function captureRef(executionId: string): string;
74
+ /**
75
+ * A single file mutation captured from the git diff between the baseline and
76
+ * after trees. `path` is repo-relative (forward slashes); `changeType` drives
77
+ * restore/apply. `before`/`after` are the harness-agnostic {@link CapturedContent}
78
+ * for each side (absent per changeType: no `before` for a CREATE, no `after` for
79
+ * a DELETE) — text is carried inline, binary carries only its byte-true content
80
+ * address (its bytes reconcile byte-exact from the git ref, never the wire).
81
+ */
82
+ export interface GitSubstrateChange {
83
+ /** Repo-relative path (the diff's path; the destination for a create/modify). */
84
+ readonly path: string;
85
+ readonly changeType: FileChangeType;
86
+ /** Pre-edit content (absent for a CREATE). */
87
+ readonly before?: CapturedContent;
88
+ /** Post-edit content (absent for a DELETE). */
89
+ readonly after?: CapturedContent;
90
+ }
91
+ /** Result of {@link captureChangeSet} / {@link recomputeChangeSet}. */
92
+ export interface CaptureResult {
93
+ /**
94
+ * The pre-turn tree sha (pinned behind the baseline ref). On resume this is
95
+ * the authoritative source for reverting rejected/undecided files exactly.
96
+ */
97
+ readonly baselineTree: string;
98
+ /** The post-turn tree sha, also pinned behind the capture ref. */
99
+ readonly afterTree: string;
100
+ /** One entry per changed file (excluding the passed runner-owned paths). */
101
+ readonly changes: readonly GitSubstrateChange[];
102
+ }
103
+ /**
104
+ * Whether `dir` is inside a git work tree (the capability switch: a real git
105
+ * workspace gets capture mode, anything else keeps the deny-gate fallback).
106
+ */
107
+ export declare function isGitWorkTree(dir: string): Promise<boolean>;
108
+ /**
109
+ * Whether a repo-relative path is capturable by this substrate — i.e. it would
110
+ * appear in the `git add -A` snapshot. A gitignored path is NOT capturable: the
111
+ * snapshot cannot see it, so it can be neither reviewed nor reverted, and a
112
+ * capture-mode gate must keep gating it. Mirrors the Cursor hook's
113
+ * `__stigmer_is_gitignored` check: `git check-ignore -q` exits 0 when the path IS
114
+ * ignored, non-zero otherwise; a non-git context / error is treated as
115
+ * not-ignored (capturable), matching the hook's allow-on-error behavior.
116
+ */
117
+ export declare function isPathCapturable(gitRoot: string, path: string): Promise<boolean>;
118
+ /**
119
+ * Snapshot the working tree at turn start and pin it behind the baseline ref.
120
+ * Returns the baseline tree sha (used by {@link captureChangeSet} and
121
+ * {@link restoreToBaseline} later in the SAME activity invocation). `excludePaths`
122
+ * are the runner-owned files the harness writes into the workspace (omit for none).
123
+ */
124
+ export declare function snapshotBaseline(gitRoot: string, executionId: string, excludePaths?: readonly string[]): Promise<string>;
125
+ /**
126
+ * Capture the change set the turn produced: write the post-turn working tree,
127
+ * pin it behind the capture ref (so it survives the approval wait), and diff it
128
+ * against `baselineTree` into a per-file {@link GitSubstrateChange} list.
129
+ *
130
+ * Renames are intentionally NOT detected (`--no-renames`): a rename surfaces as
131
+ * a delete + create, which restores and applies exactly and matches the per-file
132
+ * review model.
133
+ */
134
+ export declare function captureChangeSet(gitRoot: string, executionId: string, baselineTree: string, excludePaths?: readonly string[]): Promise<CaptureResult>;
135
+ /**
136
+ * Restore the given files to their `baselineTree` (pre-turn) bytes. On resume
137
+ * this reverts the REJECTED/undecided subset so a discarded change snaps back
138
+ * exactly; it is the generic "ensure baseline bytes" primitive. Surgical
139
+ * (bounded by the passed change set): an agent-created file is removed; an
140
+ * agent-modified or agent-deleted file is rewritten with its baseline bytes.
141
+ * `.stigmer` and other ignored paths are never touched (they are not in the
142
+ * change set). Idempotent — safe to re-run (e.g. on a Temporal retry).
143
+ */
144
+ export declare function restoreToBaseline(gitRoot: string, baselineTree: string, changes: readonly GitSubstrateChange[]): Promise<void>;
145
+ /**
146
+ * Ensure the APPROVED files hold their captured "after" bytes, as uncommitted
147
+ * working-tree changes (no commit). In capture mode the agent's edits are left
148
+ * applied through the review window, so on resume this is normally an idempotent
149
+ * re-assert of bytes already on disk; sourcing from the pinned "after" tree also
150
+ * makes it self-healing if the tree was reset (Temporal retry / sandbox
151
+ * recycle). An approved CREATE/MODIFY writes the after bytes; an approved DELETE
152
+ * removes the file. Rejected/undecided paths are not passed in (they go to
153
+ * {@link restoreToBaseline}).
154
+ */
155
+ export declare function applyApprovedPaths(gitRoot: string, afterTree: string, approved: readonly GitSubstrateChange[]): Promise<void>;
156
+ /**
157
+ * Recompute the captured change set on a RESUME, from the pinned baseline and
158
+ * capture refs — the authoritative source that survived the approval wait,
159
+ * independent of any persisted fidelity. Returns `undefined` when this was not a
160
+ * capture turn (the capture ref is absent), so the caller can fall through to the
161
+ * non-capture path.
162
+ */
163
+ export declare function recomputeChangeSet(gitRoot: string, executionId: string): Promise<CaptureResult | undefined>;
164
+ /**
165
+ * Snapshot the post-reconcile working tree (after approved bytes were applied and
166
+ * rejected files were reverted) and pin it behind the approved ref. Returns the
167
+ * approved tree sha for the RECONCILED event's `approved_snapshot`, plus the ref
168
+ * so the producer can stamp the SnapshotRef. Idempotent under a Temporal retry.
169
+ */
170
+ export declare function snapshotApproved(gitRoot: string, executionId: string, excludePaths?: readonly string[]): Promise<{
171
+ treeOid: string;
172
+ ref: string;
173
+ }>;
174
+ /** Release the per-execution baseline, capture, and approved refs (idempotent). */
175
+ export declare function dropCaptureRefs(gitRoot: string, executionId: string): Promise<void>;