@stigmer/runner 3.0.9-dev.20260616060535 → 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 (328) 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 +10 -0
  74. package/dist/activities/execute-deep-agent/hitl.js +5 -1
  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 +370 -56
  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 +11 -5
  92. package/dist/activities/execute-deep-agent/status-builder.js +6 -2
  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 +6 -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 +2 -5
  243. package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +31 -13
  244. package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +349 -0
  245. package/src/activities/execute-deep-agent/__tests__/stamp-flowed-rows.test.ts +119 -0
  246. package/src/activities/execute-deep-agent/__tests__/status-builder.test.ts +12 -11
  247. package/src/activities/execute-deep-agent/__tests__/streaming-v3.test.ts +9 -9
  248. package/src/activities/execute-deep-agent/__tests__/subagent-approval-propagation.test.ts +160 -0
  249. package/src/activities/execute-deep-agent/__tests__/subagent-gitignored-capture.test.ts +213 -0
  250. package/src/activities/execute-deep-agent/__tests__/subagent-transformer.test.ts +3 -6
  251. package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +84 -1
  252. package/src/activities/execute-deep-agent/__tests__/v3-status-builder.test.ts +4 -1
  253. package/src/activities/execute-deep-agent/approval-file-change.ts +80 -0
  254. package/src/activities/execute-deep-agent/attachment-injector.ts +20 -11
  255. package/src/activities/execute-deep-agent/cas-capture-backend.ts +66 -0
  256. package/src/activities/execute-deep-agent/cas-capture-observer.ts +125 -0
  257. package/src/activities/execute-deep-agent/hitl.ts +15 -1
  258. package/src/activities/execute-deep-agent/index.ts +434 -64
  259. package/src/activities/execute-deep-agent/inline-publisher.ts +27 -4
  260. package/src/activities/execute-deep-agent/setup.ts +223 -125
  261. package/src/activities/execute-deep-agent/stamp-flowed-rows.ts +64 -0
  262. package/src/activities/execute-deep-agent/status-builder-shared.ts +62 -23
  263. package/src/activities/execute-deep-agent/status-builder.ts +19 -7
  264. package/src/activities/execute-deep-agent/streaming-side-effects.ts +2 -16
  265. package/src/activities/execute-deep-agent/streaming.ts +3 -13
  266. package/src/activities/execute-deep-agent/subagent-transformer.ts +53 -13
  267. package/src/activities/execute-deep-agent/subagent-wiring.ts +50 -3
  268. package/src/activities/execute-deep-agent/v3-status-builder.ts +8 -2
  269. package/src/claimcheck/payload-codec.ts +8 -8
  270. package/src/client/stigmer-client.ts +9 -1
  271. package/src/middleware/__tests__/approval-gate.test.ts +488 -4
  272. package/src/middleware/approval-gate.ts +247 -38
  273. package/src/middleware/types.ts +5 -5
  274. package/src/shared/__tests__/activity-input.test.ts +78 -0
  275. package/src/shared/__tests__/approval-canonicalize.test.ts +106 -0
  276. package/src/shared/__tests__/approval-fingerprint.test.ts +115 -0
  277. package/src/shared/__tests__/approval-policy.test.ts +274 -40
  278. package/src/shared/__tests__/args-preview.test.ts +78 -0
  279. package/src/shared/__tests__/artifact-storage-extended.test.ts +62 -10
  280. package/src/shared/__tests__/artifact-storage.test.ts +123 -11
  281. package/src/shared/__tests__/file-change.test.ts +85 -0
  282. package/src/shared/__tests__/file-tools.test.ts +90 -0
  283. package/src/shared/__tests__/fingerprint-secret.test.ts +51 -0
  284. package/src/shared/__tests__/lease-scope-corpus.test.ts +56 -0
  285. package/src/shared/__tests__/model-client.test.ts +162 -0
  286. package/src/shared/__tests__/plan-artifact.test.ts +11 -26
  287. package/src/shared/__tests__/policy-source-corpus.test.ts +58 -0
  288. package/src/shared/__tests__/status-offload.test.ts +573 -16
  289. package/src/shared/__tests__/status.test.ts +4 -5
  290. package/src/shared/__tests__/tool-kind.test.ts +24 -1
  291. package/src/shared/__tests__/tool-row.test.ts +221 -0
  292. package/src/shared/activity-input.ts +57 -0
  293. package/src/shared/approval-canonicalize.ts +159 -0
  294. package/src/shared/approval-fingerprint.ts +148 -0
  295. package/src/shared/approval-policy.ts +303 -27
  296. package/src/shared/args-preview.ts +98 -0
  297. package/src/shared/artifact-storage.ts +62 -11
  298. package/src/shared/checkpointer/__tests__/http-saver.test.ts +1 -2
  299. package/src/shared/file-change.ts +64 -0
  300. package/src/shared/file-tools.ts +169 -0
  301. package/src/shared/filereview/__tests__/capture.test.ts +856 -0
  302. package/src/shared/filereview/__tests__/cas-substrate.test.ts +404 -0
  303. package/src/shared/filereview/__tests__/digest.test.ts +100 -0
  304. package/src/shared/filereview/__tests__/events.test.ts +245 -0
  305. package/src/shared/filereview/__tests__/git-substrate.test.ts +362 -0
  306. package/src/shared/filereview/__tests__/proxy-reconcile.test.ts +286 -0
  307. package/src/shared/filereview/__tests__/secret-paths.test.ts +121 -0
  308. package/src/shared/filereview/capture.ts +727 -0
  309. package/src/shared/filereview/cas-substrate.ts +401 -0
  310. package/src/shared/filereview/digest.ts +83 -0
  311. package/src/shared/filereview/events.ts +449 -0
  312. package/src/shared/filereview/git-substrate.ts +555 -0
  313. package/src/shared/filereview/index.ts +60 -0
  314. package/src/shared/filereview/secret-paths.ts +121 -0
  315. package/src/shared/fingerprint-secret.ts +53 -0
  316. package/src/shared/model-client.ts +122 -0
  317. package/src/shared/plan-artifact.ts +0 -2
  318. package/src/shared/status-offload.ts +433 -77
  319. package/src/shared/status.ts +13 -0
  320. package/src/shared/tool-kind.ts +33 -0
  321. package/src/shared/tool-row.ts +135 -0
  322. package/src/shared/workspace/platform-dir.ts +41 -2
  323. package/src/workflow-engine/__tests__/golden-execution.test.ts +35 -18
  324. package/src/workflow-engine/__tests__/tasks/try.test.ts +1 -1
  325. package/src/workflows/__tests__/connect-mcp-server.test.ts +304 -29
  326. package/src/workflows/call-agent-orchestrator.ts +53 -6
  327. package/src/workflows/connect-mcp-server.ts +179 -24
  328. package/src/workflows/types.ts +8 -0
@@ -0,0 +1,449 @@
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
+
14
+ import { create } from "@bufbuild/protobuf";
15
+ import type { AgentExecutionStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
16
+ import {
17
+ CapturedFileChangeSchema,
18
+ FileReviewBaselineCapturedSchema,
19
+ FileReviewCandidateCapturedSchema,
20
+ FileReviewEventSchema,
21
+ FileReviewEventStreamSchema,
22
+ FileReviewFailureSchema,
23
+ FileReviewReconciledSchema,
24
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/filereview_pb";
25
+ import type {
26
+ CapturedFileChange,
27
+ FileReviewEvent,
28
+ SnapshotRef,
29
+ TurnCommandProvenance,
30
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/filereview_pb";
31
+ import {
32
+ FileContentSchema,
33
+ ToolCallOutputRefSchema,
34
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
35
+ import type { FileContent } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
36
+ import {
37
+ DiffCompleteness,
38
+ FileCaptureClass,
39
+ FileChangeKind,
40
+ FileReviewBlockReason,
41
+ FileReviewEventType,
42
+ FileReviewFailureKind,
43
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
44
+ import { aggregateDigest, fileDigest, sha256Bytes } from "./digest.js";
45
+ import { looksBinary } from "../file-change.js";
46
+
47
+ // The runner is the author of capture/reconcile/failure events. "runner" (not
48
+ // the generic "system") matches the cross-edition corpus fixtures and the
49
+ // proto's actor convention ("runner" for capture/reconcile, "user" for
50
+ // decisions). The projection ignores actor, but keeping it canonical keeps the
51
+ // ledger self-describing and the dual-edition corpus honest.
52
+ const ACTOR_RUNNER = "runner";
53
+
54
+ /**
55
+ * The proto enum value NAME for a {@link FileReviewEventType}, e.g.
56
+ * `FILE_REVIEW_EVENT_TYPE_BASELINE_CAPTURED`. {@link eventId} hashes this name so
57
+ * the runner's ids are byte-identical to the Go `author.EventID` / Java
58
+ * `FileReviewStreamAuthor.eventId` (which use the proto name).
59
+ */
60
+ const FILE_REVIEW_EVENT_TYPE_NAME: Readonly<Record<FileReviewEventType, string>> = {
61
+ [FileReviewEventType.UNSPECIFIED]: "FILE_REVIEW_EVENT_TYPE_UNSPECIFIED",
62
+ [FileReviewEventType.BASELINE_CAPTURED]: "FILE_REVIEW_EVENT_TYPE_BASELINE_CAPTURED",
63
+ [FileReviewEventType.CANDIDATE_CAPTURED]: "FILE_REVIEW_EVENT_TYPE_CANDIDATE_CAPTURED",
64
+ [FileReviewEventType.FILE_DECIDED]: "FILE_REVIEW_EVENT_TYPE_FILE_DECIDED",
65
+ [FileReviewEventType.RECONCILED]: "FILE_REVIEW_EVENT_TYPE_RECONCILED",
66
+ [FileReviewEventType.FAILED]: "FILE_REVIEW_EVENT_TYPE_FAILED",
67
+ };
68
+
69
+ /**
70
+ * The deterministic idempotency key for a file-review event:
71
+ * `changeSetId:scopeId:eventTypeName`. Capture/reconcile/failure events are
72
+ * change-set-scoped (scopeId == changeSetId); the per-file decision scope is the
73
+ * server's concern. Identical to the Go/Java EventID.
74
+ */
75
+ export function eventId(
76
+ changeSetId: string,
77
+ scopeId: string,
78
+ type: FileReviewEventType,
79
+ ): string {
80
+ return `${changeSetId}:${scopeId}:${FILE_REVIEW_EVENT_TYPE_NAME[type]}`;
81
+ }
82
+
83
+ /**
84
+ * One side (before/after) of a captured file's content, in one of three shapes:
85
+ *
86
+ * - `inline` — the raw text bytes, carried on the wire (the git substrate reads
87
+ * them from the tree for text files). A plain string is accepted as shorthand.
88
+ * - `ref` — a reference to an already-stored, content-addressed blob (the CAS
89
+ * substrate offloads ignored / non-git bodies to artifact storage and carries
90
+ * the ref, so the body is never stored twice).
91
+ * - `binary` — a git-tracked binary side: NO body is carried (a binary has no
92
+ * reviewable text diff, and reconcile sources its bytes byte-exact from the
93
+ * git ref, never from the wire), only the byte-true content address. This is
94
+ * what keeps the enforcement digest honest for binaries — hashing a UTF-8
95
+ * decode of binary bytes would be lossy.
96
+ */
97
+ export type CapturedContent =
98
+ | {
99
+ readonly kind: "inline";
100
+ readonly text: string;
101
+ /**
102
+ * Byte-true SHA-256 of the RAW bytes, when the producer computed it at the
103
+ * source (the git substrate does). Preferred over hashing `text`, which for
104
+ * a non-UTF-8 blob (e.g. latin-1 with no NUL) would hash a lossy decode.
105
+ * Absent for the plain-string shorthand, where `text` IS the exact content.
106
+ */
107
+ readonly sha256?: string;
108
+ }
109
+ | {
110
+ readonly kind: "ref";
111
+ /** Content address of the referenced blob (the enforcement digest). */
112
+ readonly sha256: string;
113
+ readonly storageKey: string;
114
+ readonly sizeBytes: number;
115
+ readonly isBinary: boolean;
116
+ readonly mimeType?: string;
117
+ }
118
+ | {
119
+ readonly kind: "binary";
120
+ /** Byte-true SHA-256 of the raw bytes (the enforcement digest). */
121
+ readonly sha256: string;
122
+ };
123
+
124
+ /** A single captured file delta, harness-agnostic (no git/CAS specifics). */
125
+ export interface CapturedChangeInput {
126
+ /** Stable id of this file change within its set (correlation key, never a hash). */
127
+ readonly id: string;
128
+ /** Path before the change (workspace-root-relative). Empty for ADD. */
129
+ readonly pathBefore: string;
130
+ /** Path after the change. Empty for DELETE; differs from pathBefore for RENAME. */
131
+ readonly pathAfter: string;
132
+ readonly kind: FileChangeKind;
133
+ /** Which substrate captured this file (git-tracked, ignored, CAS, ...). */
134
+ readonly captureClass: FileCaptureClass;
135
+ /** Pre-edit content (inline string, or a blob ref). Omit for ADD. */
136
+ readonly before?: string | CapturedContent;
137
+ /** Post-edit content (inline string, or a blob ref). Omit for DELETE. */
138
+ readonly after?: string | CapturedContent;
139
+ /**
140
+ * False when this file's diff could not be captured completely (too large to
141
+ * persist inline before CAS exists, truncated, or binary-only). A change set
142
+ * with any incomplete file cannot be approved as complete.
143
+ */
144
+ readonly diffComplete?: boolean;
145
+ /**
146
+ * The honest cause the diff is not fully reviewable, set only alongside
147
+ * `diffComplete === false` (defaults to UNSPECIFIED). Informational provenance
148
+ * for the review UI — never an enforcement input and never folded into the
149
+ * digests. Binary is conveyed by FileContent.is_binary, so binary files leave
150
+ * this UNSPECIFIED. See {@link FileReviewBlockReason}.
151
+ */
152
+ readonly blockedReason?: FileReviewBlockReason;
153
+ }
154
+
155
+ /** Normalize the string-shorthand to a {@link CapturedContent}. */
156
+ function normalizeContent(v: string | CapturedContent | undefined): CapturedContent | undefined {
157
+ if (v === undefined) return undefined;
158
+ return typeof v === "string" ? { kind: "inline", text: v } : v;
159
+ }
160
+
161
+ /**
162
+ * The enforcement digest of one content side. Inline text is hashed as UTF-8
163
+ * bytes; a `ref`/`binary` side already carries its byte-true content address, so
164
+ * it is reused verbatim. This single function is the sole sha authority — used
165
+ * both at capture (in {@link buildCapturedFileChange}) and at the resume-time
166
+ * reconcile check — so the two are consistent by construction across substrates.
167
+ */
168
+ export function contentSha256(content: CapturedContent): string {
169
+ switch (content.kind) {
170
+ case "inline":
171
+ return content.sha256 ?? sha256Bytes(Buffer.from(content.text, "utf8"));
172
+ case "ref":
173
+ case "binary":
174
+ return content.sha256;
175
+ }
176
+ }
177
+
178
+ /** Build the proto {@link FileContent} for one content side (inline, ref, or binary). */
179
+ function toFileContent(content: CapturedContent): FileContent {
180
+ if (content.kind === "inline") {
181
+ return create(FileContentSchema, {
182
+ body: { case: "inline", value: content.text },
183
+ isBinary: looksBinary(content.text),
184
+ });
185
+ }
186
+ // A git-tracked binary carries no body: its bytes reconcile from the git ref,
187
+ // and a text diff of binary content is meaningless. Consumers key off the
188
+ // is_binary flag (the SDK renders "binary file changed"; the backend gates
189
+ // approval on it), never a body.
190
+ if (content.kind === "binary") {
191
+ return create(FileContentSchema, { isBinary: true });
192
+ }
193
+ return create(FileContentSchema, {
194
+ body: {
195
+ case: "ref",
196
+ value: create(ToolCallOutputRefSchema, {
197
+ storageKey: content.storageKey,
198
+ sizeBytes: BigInt(content.sizeBytes),
199
+ contentHash: content.sha256,
200
+ mimeType: content.mimeType ?? "application/octet-stream",
201
+ isImage: false,
202
+ truncatedPreview: "",
203
+ }),
204
+ },
205
+ isBinary: content.isBinary,
206
+ });
207
+ }
208
+
209
+ /**
210
+ * Build a proto {@link CapturedFileChange} from harness-agnostic input,
211
+ * computing the enforcement digests (`before_sha256`, `after_sha256`,
212
+ * `file_digest`) over the captured bytes. Content may be inline (git) or a blob
213
+ * ref (CAS) — the digests are identical either way, so the aggregate digest and
214
+ * the reconcile enforcement compose across both substrates.
215
+ */
216
+ export function buildCapturedFileChange(input: CapturedChangeInput): CapturedFileChange {
217
+ const before = normalizeContent(input.before);
218
+ const after = normalizeContent(input.after);
219
+ const beforeSha256 = before ? contentSha256(before) : "";
220
+ const afterSha256 = after ? contentSha256(after) : "";
221
+
222
+ const fc = create(CapturedFileChangeSchema, {
223
+ id: input.id,
224
+ pathBefore: input.pathBefore,
225
+ pathAfter: input.pathAfter,
226
+ kind: input.kind,
227
+ captureClass: input.captureClass,
228
+ beforeSha256,
229
+ afterSha256,
230
+ diffComplete: input.diffComplete ?? true,
231
+ blockedReason: input.blockedReason ?? FileReviewBlockReason.UNSPECIFIED,
232
+ fileDigest: fileDigest({
233
+ pathBefore: input.pathBefore,
234
+ pathAfter: input.pathAfter,
235
+ kind: input.kind,
236
+ beforeSha256,
237
+ afterSha256,
238
+ }),
239
+ });
240
+ if (before) {
241
+ fc.before = toFileContent(before);
242
+ }
243
+ if (after) {
244
+ fc.after = toFileContent(after);
245
+ }
246
+ return fc;
247
+ }
248
+
249
+ /** Coordinates a change set's lifecycle so every event carries one identity. */
250
+ export interface ChangeSetContext {
251
+ readonly changeSetId: string;
252
+ readonly turnId: string;
253
+ /** "cursor" | "deep-agent". */
254
+ readonly harnessId: string;
255
+ /** ISO 8601 timestamp authored onto each event. */
256
+ readonly timestamp: string;
257
+ }
258
+
259
+ /**
260
+ * The BASELINE_CAPTURED event — the first event of a change set's lifecycle,
261
+ * authored at turn start so the projection can materialize the set before any
262
+ * candidate exists.
263
+ */
264
+ export function buildBaselineCapturedEvent(
265
+ ctx: ChangeSetContext,
266
+ baselineSnapshot: SnapshotRef | undefined,
267
+ ): FileReviewEvent {
268
+ return create(FileReviewEventSchema, {
269
+ eventId: eventId(ctx.changeSetId, ctx.changeSetId, FileReviewEventType.BASELINE_CAPTURED),
270
+ changeSetId: ctx.changeSetId,
271
+ eventType: FileReviewEventType.BASELINE_CAPTURED,
272
+ timestamp: ctx.timestamp,
273
+ actor: ACTOR_RUNNER,
274
+ payload: {
275
+ case: "baselineCaptured",
276
+ value: create(FileReviewBaselineCapturedSchema, {
277
+ changeSetId: ctx.changeSetId,
278
+ turnId: ctx.turnId,
279
+ harnessId: ctx.harnessId,
280
+ ...(baselineSnapshot ? { baselineSnapshot } : {}),
281
+ }),
282
+ },
283
+ });
284
+ }
285
+
286
+ /**
287
+ * Derive a change set's {@link DiffCompleteness} rollup from its per-file
288
+ * signals — the single source of the three-way rule, shared by the turn-boundary
289
+ * capture ({@link buildCandidateCapturedEvent}) and the size backstop
290
+ * (status-offload), so the value can never be computed two ways:
291
+ *
292
+ * - every file complete → `COMPLETE`
293
+ * - else the ONLY incompleteness is binary (every incomplete file has a binary
294
+ * side) → `BINARY_SUMMARY_ONLY` — keepable in one acknowledged action, its
295
+ * exact bytes reconcile from the git ref / CAS blob
296
+ * - else (≥1 non-binary incomplete: secret-withheld / size-elided /
297
+ * uncapturable — no keepable bytes) → `PARTIAL_BLOCKED`
298
+ *
299
+ * Binary is proven by `FileContent.is_binary` on either side (DD-15 D2), never
300
+ * by the block reason. This mirrors the backend gate's `isBinaryChange`, so the
301
+ * runner's rollup and the gate's per-file re-derivation agree by construction.
302
+ */
303
+ export function deriveDiffCompleteness(
304
+ changes: readonly CapturedFileChange[],
305
+ ): DiffCompleteness {
306
+ let sawIncomplete = false;
307
+ for (const c of changes) {
308
+ if (c.diffComplete) continue;
309
+ sawIncomplete = true;
310
+ if (!(c.before?.isBinary || c.after?.isBinary)) {
311
+ // A non-binary incompleteness has no keepable bytes — it blocks the set
312
+ // outright, regardless of any binaries alongside it.
313
+ return DiffCompleteness.PARTIAL_BLOCKED;
314
+ }
315
+ }
316
+ if (!sawIncomplete) return DiffCompleteness.COMPLETE;
317
+ return DiffCompleteness.BINARY_SUMMARY_ONLY;
318
+ }
319
+
320
+ /**
321
+ * The CANDIDATE_CAPTURED event — authored at the turn boundary, carrying the
322
+ * authoritative per-file diff and the aggregate digest. `diff_completeness` is
323
+ * the {@link deriveDiffCompleteness} rollup over the changes.
324
+ *
325
+ * `commandProvenance` (optional, DD-28) is the harness's approved-command turn
326
+ * facts: when present, the backend verifies the cited consent rows against its
327
+ * server-authored approval record and — on success — auto-keeps the set with a
328
+ * policy-origin decision instead of arming the review gate. Never folded into
329
+ * the aggregate digest (provenance, not content).
330
+ */
331
+ export function buildCandidateCapturedEvent(
332
+ ctx: ChangeSetContext,
333
+ candidateSnapshot: SnapshotRef | undefined,
334
+ changes: readonly CapturedFileChange[],
335
+ commandProvenance?: TurnCommandProvenance,
336
+ ): FileReviewEvent {
337
+ return create(FileReviewEventSchema, {
338
+ eventId: eventId(ctx.changeSetId, ctx.changeSetId, FileReviewEventType.CANDIDATE_CAPTURED),
339
+ changeSetId: ctx.changeSetId,
340
+ eventType: FileReviewEventType.CANDIDATE_CAPTURED,
341
+ timestamp: ctx.timestamp,
342
+ actor: ACTOR_RUNNER,
343
+ payload: {
344
+ case: "candidateCaptured",
345
+ value: create(FileReviewCandidateCapturedSchema, {
346
+ changeSetId: ctx.changeSetId,
347
+ ...(candidateSnapshot ? { candidateSnapshot } : {}),
348
+ changes: [...changes],
349
+ aggregateDigest: aggregateDigest(
350
+ changes.map((c) => ({
351
+ pathBefore: c.pathBefore,
352
+ pathAfter: c.pathAfter,
353
+ kind: c.kind,
354
+ beforeSha256: c.beforeSha256,
355
+ afterSha256: c.afterSha256,
356
+ })),
357
+ ),
358
+ diffCompleteness: deriveDiffCompleteness(changes),
359
+ ...(commandProvenance ? { commandProvenance } : {}),
360
+ }),
361
+ },
362
+ });
363
+ }
364
+
365
+ /** The RECONCILED event — authored after decisions are applied and verified. */
366
+ export function buildReconciledEvent(
367
+ ctx: ChangeSetContext,
368
+ approvedSnapshot: SnapshotRef | undefined,
369
+ ): FileReviewEvent {
370
+ return create(FileReviewEventSchema, {
371
+ eventId: eventId(ctx.changeSetId, ctx.changeSetId, FileReviewEventType.RECONCILED),
372
+ changeSetId: ctx.changeSetId,
373
+ eventType: FileReviewEventType.RECONCILED,
374
+ timestamp: ctx.timestamp,
375
+ actor: ACTOR_RUNNER,
376
+ payload: {
377
+ case: "reconciled",
378
+ value: create(FileReviewReconciledSchema, {
379
+ changeSetId: ctx.changeSetId,
380
+ ...(approvedSnapshot ? { approvedSnapshot } : {}),
381
+ }),
382
+ },
383
+ });
384
+ }
385
+
386
+ /** A terminal FAILED event in the file-review lifecycle (audit + resume). */
387
+ export function buildFailedEvent(
388
+ ctx: ChangeSetContext,
389
+ kind: FileReviewFailureKind,
390
+ detail: string,
391
+ ): FileReviewEvent {
392
+ return create(FileReviewEventSchema, {
393
+ eventId: eventId(ctx.changeSetId, ctx.changeSetId, FileReviewEventType.FAILED),
394
+ changeSetId: ctx.changeSetId,
395
+ eventType: FileReviewEventType.FAILED,
396
+ timestamp: ctx.timestamp,
397
+ actor: ACTOR_RUNNER,
398
+ payload: {
399
+ case: "failed",
400
+ value: create(FileReviewFailureSchema, { changeSetId: ctx.changeSetId, kind, detail }),
401
+ },
402
+ });
403
+ }
404
+
405
+ /**
406
+ * Whether a CANDIDATE_CAPTURED event exists for `changeSetId` on the status's
407
+ * file_review stream — i.e. this turn actually produced a reviewable change
408
+ * set. The capture seam authors no event for a no-op turn (an edit fully
409
+ * reverted before the boundary), so this is the single signal both harnesses
410
+ * gate on before opening a review or stamping transcript rows: a row must
411
+ * never reference a change set that does not exist.
412
+ */
413
+ export function hasCandidateCaptured(
414
+ status: AgentExecutionStatus,
415
+ changeSetId: string,
416
+ ): boolean {
417
+ return (status.fileReviewEventStream?.events ?? []).some(
418
+ (e) =>
419
+ e.changeSetId === changeSetId &&
420
+ e.eventType === FileReviewEventType.CANDIDATE_CAPTURED,
421
+ );
422
+ }
423
+
424
+ /**
425
+ * Append the runner-authored events onto the status's file_review stream
426
+ * (seeding it if absent), idempotently by event_id. The server re-applies the
427
+ * same append-only/by-id discipline on receipt, so re-sending across throttled
428
+ * persists is safe; this keeps the in-runner status consistent between persists.
429
+ */
430
+ export function appendFileReviewEvents(
431
+ status: AgentExecutionStatus,
432
+ executionId: string,
433
+ events: readonly FileReviewEvent[],
434
+ ): void {
435
+ if (events.length === 0) return;
436
+ if (!status.fileReviewEventStream) {
437
+ status.fileReviewEventStream = create(FileReviewEventStreamSchema, {
438
+ executionId,
439
+ events: [],
440
+ });
441
+ }
442
+ const stream = status.fileReviewEventStream;
443
+ const seen = new Set(stream.events.map((e) => e.eventId));
444
+ for (const ev of events) {
445
+ if (seen.has(ev.eventId)) continue;
446
+ seen.add(ev.eventId);
447
+ stream.events.push(ev);
448
+ }
449
+ }