@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
@@ -16,46 +16,107 @@
16
16
  * pausing again.
17
17
  *
18
18
  * Platform tool defaults: DeepAgents JS backend tools (read, write,
19
- * edit, execute, etc.) are not covered by MCP policy chains. This
20
- * middleware applies sensible defaults: read-only tools are auto-approved,
21
- * mutating tools require approval when no explicit policy exists.
19
+ * edit, execute, etc.) are not covered by MCP policy chains. Built-in tools
20
+ * are classified through the shared {@link toolApprovalCategory} — the single
21
+ * source of truth, shared with the Cursor deny-oracle hook — so read-only tools
22
+ * are auto-approved and every mutating tool (write/edit/delete/shell) is gated
23
+ * fail-CLOSED, by category rather than by a hand-maintained name list. An
24
+ * unrecognized mutating built-in (e.g. `bash`, `overwrite_file`) is therefore
25
+ * gated by what it does, not by whether someone remembered to list it.
26
+ *
27
+ * Gateway invariant (Phase 2): this middleware IS the in-process execution
28
+ * gateway for the deep-agent harness — `handler(request)` is the side effect. A
29
+ * side effect runs only with a backing authorization: either (a) the tool was
30
+ * auto-approved (policy/classifier cleared it, or auto-approve-all disabled the
31
+ * whole gate), or (b) the user explicitly approved THIS interrupted call. Every
32
+ * other outcome — skip, reject, or an unrecognized decision — returns a
33
+ * ToolMessage WITHOUT executing. There is no path from a model proposal to a
34
+ * side effect that skips an authorization.
35
+ *
36
+ * Shadow ExecutionReceipt: when the gateway lets a side effect through it emits a
37
+ * structured, non-persisted receipt (a `[hitl-gateway] receipt …` log carrying
38
+ * the action's HMAC fingerprint and the authorization source). This is an audit
39
+ * + uniformity signal only — no proto, no storage — mirroring the Phase-1 shadow
40
+ * discipline. On the deep-agent normal path the fingerprint match is guaranteed
41
+ * by LangGraph checkpoint replay (the resumed action equals the approved one), so
42
+ * the receipt is defense-in-depth here; the fingerprint earns real enforcement
43
+ * teeth in the out-of-process Cursor substrate.
22
44
  */
23
45
  import { ToolMessage } from "@langchain/core/messages";
24
46
  import { interrupt } from "@langchain/langgraph";
25
- import { resolveApprovalMessage, } from "../shared/approval-policy.js";
26
- const SAFE_PLATFORM_TOOLS = new Set([
27
- "read", "read_file",
28
- "ls", "list_directory",
29
- "glob", "find_files",
30
- "grep", "search", "ripgrep",
31
- "think",
32
- ]);
33
- const DANGEROUS_PLATFORM_TOOLS = new Map([
34
- ["write", "Write file: {{args.path}}"],
35
- ["write_file", "Write file: {{args.path}}"],
36
- ["edit", "Edit file: {{args.path}}"],
37
- ["edit_file", "Edit file: {{args.path}}"],
38
- ["create", "Create file: {{args.path}}"],
39
- ["create_file", "Create file: {{args.path}}"],
40
- ["delete", "Delete: {{args.path}}"],
41
- ["delete_file", "Delete file: {{args.path}}"],
42
- ["execute", "Execute command: {{args.command}}"],
43
- ["shell", "Execute shell command: {{args.command}}"],
44
- ["str_replace_editor", "Edit file: {{args.path}}"],
45
- ]);
47
+ import { POLICY_ENGINE_VERSION, resolveApprovalMessage, } from "../shared/approval-policy.js";
48
+ import { toolApprovalCategory } from "../shared/tool-kind.js";
49
+ import { extractFilePath } from "../shared/file-tools.js";
50
+ import { isSecretLikePath } from "../shared/filereview/secret-paths.js";
51
+ import { computeApprovalFingerprint, } from "../shared/approval-fingerprint.js";
52
+ // Approval-message template per mutating category. Keyed by category (not raw
53
+ // tool name) so every alias of a mutation renders one message; placeholders
54
+ // resolve against the deep-agent stream arg shape (`path`/`command`). Mirrors
55
+ // the Cursor side's CATEGORY_APPROVAL_MESSAGE.
56
+ const CATEGORY_APPROVAL_MESSAGE = {
57
+ write: "Write file: {{args.path}}",
58
+ delete: "Delete: {{args.path}}",
59
+ shell: "Execute command: {{args.command}}",
60
+ };
46
61
  export function createApprovalGateMiddleware(config) {
47
- const { policies, autoApproveAll, toolServerMap } = config;
48
- if (autoApproveAll) {
49
- return { name: "ApprovalGateMiddleware" };
50
- }
62
+ const { policies, toolServerMap } = config;
63
+ const leasedCategories = config.leasedCategories ?? EMPTY_CATEGORY_SET;
64
+ // No global-bypass early return: a pre-armed spec.auto_approve_all means the
65
+ // gate is never even installed (setup.ts builds this config only when not
66
+ // global). Scoped leases keep the gate active so non-leased actions still gate.
51
67
  return {
52
68
  name: "ApprovalGateMiddleware",
53
69
  async wrapToolCall(request, handler) {
54
70
  const { toolCall } = request;
55
71
  const toolName = toolCall.name;
56
72
  const serverSlug = toolServerMap.get(toolName) ?? "";
57
- const requirement = resolveToolApproval(toolName, serverSlug, toolCall.args, policies);
73
+ const category = toolApprovalCategory(toolName);
74
+ // Capture mode (git workspaces): a git-tracked built-in file mutation flows
75
+ // during the turn and is reviewed post-hoc via the file_review ledger (the
76
+ // apply-then-review model). shell and MCP tools (serverSlug present) are
77
+ // never bypassed here.
78
+ if (config.fileCaptureMode &&
79
+ config.isCapturablePath &&
80
+ !serverSlug &&
81
+ (category === "write" || category === "delete")) {
82
+ const path = extractFilePath(toolCall.args);
83
+ if (path !== null) {
84
+ if (await config.isCapturablePath(path)) {
85
+ // Git-tracked: flows and is reviewed post-hoc by the git substrate.
86
+ emitExecutionReceipt(config, toolCall, serverSlug, category, "auto_approve", "file_capture");
87
+ return await handler(request);
88
+ }
89
+ // Gitignored path. Only the PARENT gate (captureIgnored) routes it into
90
+ // CAS capture; sub-agent gates fall through to the interrupt gate below,
91
+ // exactly as before (their backends are not CAS-observed).
92
+ if (config.captureIgnored) {
93
+ if (isSecretLikePath(path)) {
94
+ // DD-E fail-closed: a secret-like gitignored edit is NEVER applied
95
+ // and NEVER captured. Record it so the turn boundary authors a
96
+ // DIFF_UNREVIEWABLE entry (blocking approval); nothing is written.
97
+ config.recordBlockedSecret?.(path);
98
+ return new ToolMessage({
99
+ content: `Tool '${toolName}' was blocked for security: '${path}' matches a ` +
100
+ `secret-like path Stigmer will not capture for review. Nothing was written.`,
101
+ tool_call_id: toolCall.id,
102
+ name: toolName,
103
+ });
104
+ }
105
+ if (category === "write") {
106
+ // Non-secret gitignored write/edit: flows (apply-then-review). The
107
+ // CAS observer already holds its before-bytes and the turn boundary
108
+ // captures it into CAS. (A gitignored delete has no backend capture
109
+ // path, so it falls through to the interrupt gate.)
110
+ emitExecutionReceipt(config, toolCall, serverSlug, category, "auto_approve", "file_capture");
111
+ return await handler(request);
112
+ }
113
+ }
114
+ }
115
+ }
116
+ const requirement = resolveToolApproval(toolName, serverSlug, toolCall.args, policies, leasedCategories);
58
117
  if (!requirement.requiresApproval) {
118
+ // Backing authorization: the classifier/policy auto-approved this tool.
119
+ emitExecutionReceipt(config, toolCall, serverSlug, category, "auto_approve", requirement.source);
59
120
  return await handler(request);
60
121
  }
61
122
  const approvalRequest = {
@@ -63,12 +124,18 @@ export function createApprovalGateMiddleware(config) {
63
124
  tool_name: toolName,
64
125
  mcp_server_slug: serverSlug,
65
126
  message: requirement.message,
127
+ // Carry the gate's provenance verdict through the interrupt so the
128
+ // reinvocation that seeds the WAITING_APPROVAL tool call (index.ts) can
129
+ // persist ToolCall.approval_policy_source without re-deriving it.
130
+ policy_source: requirement.source,
66
131
  };
67
132
  const response = interrupt(approvalRequest);
68
133
  const action = (typeof response === "object" && response !== null
69
134
  ? (response.action ?? "")
70
135
  : "").toString().toLowerCase();
71
136
  if (action === "approve") {
137
+ // Backing authorization: the user approved THIS interrupted call.
138
+ emitExecutionReceipt(config, toolCall, serverSlug, category, "approval", requirement.source);
72
139
  return await handler(request);
73
140
  }
74
141
  if (action === "skip") {
@@ -98,28 +165,88 @@ export function createApprovalGateMiddleware(config) {
98
165
  },
99
166
  };
100
167
  }
101
- function resolveToolApproval(toolName, serverSlug, args, policies) {
168
+ function resolveToolApproval(toolName, serverSlug, args, policies, leasedCategories) {
102
169
  if (serverSlug) {
170
+ // MCP tools stay governed by the connect-flow classifier + four-level policy
171
+ // chain. The policy map carries only the tools that REQUIRE approval, so an
172
+ // absent entry means the classifier already auto-approved it — fail-OPEN is
173
+ // correct here (a fail-closed default would re-gate everything the classifier
174
+ // cleared). This is deliberately NOT changed by the built-in fail-closed flip.
175
+ //
176
+ // A server-scoped lease surfaces here as an absent entry too: the leased
177
+ // server's tools are dropped from `policies` upstream (mergeApprovalPolicies),
178
+ // so a lease-cleared MCP tool takes this same auto-approve path. (Its shadow
179
+ // receipt therefore reads classifier_default rather than approval_lease; a
180
+ // faithful per-server lease provenance would need the lease set threaded here
181
+ // and is deferred with the rest of the persisted-receipt work.)
103
182
  const key = `${serverSlug}/${toolName}`;
104
183
  const policy = policies.get(key);
105
184
  if (policy) {
106
185
  return {
107
186
  requiresApproval: policy.requiresApproval,
108
187
  message: resolveApprovalMessage(policy.approvalMessage, toolName, args),
188
+ source: policy.source,
109
189
  };
110
190
  }
111
- return { requiresApproval: false, message: "" };
112
- }
113
- if (SAFE_PLATFORM_TOOLS.has(toolName)) {
114
- return { requiresApproval: false, message: "" };
191
+ // Absent = cleared by the MCP four-level chain (classifier base) or by a
192
+ // server-scoped lease (dropped upstream).
193
+ return { requiresApproval: false, message: "", source: "classifier_default" };
115
194
  }
116
- const dangerousTemplate = DANGEROUS_PLATFORM_TOOLS.get(toolName);
117
- if (dangerousTemplate) {
195
+ // Built-in/platform tool: gate exactly the mutating categories via the shared
196
+ // classifier. Fail-CLOSED for the mutating set — any built-in classifyTool
197
+ // deems write/edit/delete/shell requires approval. Read-only and unclassified
198
+ // built-ins are not mutating, so they remain fail-open.
199
+ const category = toolApprovalCategory(toolName);
200
+ if (category) {
201
+ // Run-lifetime category lease: the user chose "approve all <category>"
202
+ // earlier in this run, so every built-in of that category is auto-approved
203
+ // for the rest of the run (the scoped successor to auto-approve-all).
204
+ if (leasedCategories.has(category)) {
205
+ return { requiresApproval: false, message: "", source: "approval_lease" };
206
+ }
118
207
  return {
119
208
  requiresApproval: true,
120
- message: resolveApprovalMessage(dangerousTemplate, toolName, args),
209
+ message: resolveApprovalMessage(CATEGORY_APPROVAL_MESSAGE[category], toolName, args),
210
+ source: "builtin_category",
121
211
  };
122
212
  }
123
- return { requiresApproval: false, message: "" };
213
+ return { requiresApproval: false, message: "", source: "builtin_category" };
214
+ }
215
+ /** Shared empty set so a config without leases allocates nothing per call. */
216
+ const EMPTY_CATEGORY_SET = new Set();
217
+ /**
218
+ * Emit the shadow ExecutionReceipt when the gateway authorizes a side effect.
219
+ *
220
+ * Scope: only side-effecting actions are recorded — a mutating built-in (a
221
+ * non-empty {@link ToolApprovalCategory}) or any MCP tool (`serverSlug` present).
222
+ * Read-only built-ins are not side effects, so recording them would only dilute
223
+ * the signal. The receipt is a structured log carrying the action's HMAC
224
+ * fingerprint and the authorization source; it is never persisted and crosses no
225
+ * wire (no proto). The fingerprint is omitted (empty) when no per-execution key
226
+ * was supplied (tests / no-secret paths).
227
+ */
228
+ function emitExecutionReceipt(config, toolCall, serverSlug, category, source, policySource) {
229
+ if (!category && !serverSlug)
230
+ return;
231
+ const fingerprint = config.fingerprintKey
232
+ ? computeApprovalFingerprint(config.fingerprintKey, {
233
+ toolName: toolCall.name,
234
+ mcpServerSlug: serverSlug,
235
+ args: toolCall.args,
236
+ })
237
+ : "";
238
+ console.log("[hitl-gateway] receipt " +
239
+ JSON.stringify({
240
+ executionId: config.executionId ?? "",
241
+ toolCallId: toolCall.id,
242
+ toolName: toolCall.name,
243
+ mcpServerSlug: serverSlug,
244
+ category: category ?? "",
245
+ authorization: source,
246
+ policySource,
247
+ policyEngineVersion: POLICY_ENGINE_VERSION,
248
+ fingerprint,
249
+ substrate: "deep-agent",
250
+ }));
124
251
  }
125
252
  //# sourceMappingURL=approval-gate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"approval-gate.js","sourceRoot":"","sources":["../../src/middleware/approval-gate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"approval-gate.js","sourceRoot":"","sources":["../../src/middleware/approval-gate.ts"],"names":[],"mappings":"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"}
@@ -81,11 +81,8 @@ export interface CostCapConfig {
81
81
  export interface OtelSpansConfig {
82
82
  readonly toolServerMap: ReadonlyMap<string, string>;
83
83
  }
84
- export interface ApprovalGateConfig {
85
- readonly policies: ReadonlyMap<string, import("../shared/approval-policy.js").MergedToolPolicy>;
86
- readonly autoApproveAll: boolean;
87
- readonly toolServerMap: ReadonlyMap<string, string>;
88
- }
84
+ import type { ApprovalGateConfig } from "./approval-gate.js";
85
+ export type { ApprovalGateConfig };
89
86
  /**
90
87
  * Top-level configuration for buildMiddlewareStack().
91
88
  * All sections are optional — the factory applies sensible defaults.
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Typed Temporal activity input shared by ExecuteCursor and ExecuteDeepAgent.
3
+ *
4
+ * The Go and Java control planes now invoke these activities with a single
5
+ * object carrying snake_case keys (mirroring the polyglot workflow-input
6
+ * convention) instead of positional string args. This ends the prior drift
7
+ * where Go sent (executionId, threadId) and Java sent
8
+ * (executionId, threadId, invokerIdentityAccountId) while this single runner
9
+ * read only the first two positionally.
10
+ *
11
+ * TRANSITIONAL DUAL-SHAPE: the activity is MaximumAttempts=1 (a failed activity
12
+ * fails the execution with no retry), and the control plane and this runner
13
+ * deploy separately. To make the rollout order-independent, the runner accepts
14
+ * BOTH the new object and the legacy positional args. Deploy the runner first,
15
+ * then the control planes; once both are everywhere, drop the positional branch
16
+ * (and the `string` arms below).
17
+ */
18
+ export interface ExecuteActivityInput {
19
+ readonly execution_id: string;
20
+ readonly thread_id: string;
21
+ /** Carried for cross-edition parity; the runner hydrates the invoker from the DB. */
22
+ readonly invoker_identity_account_id?: string;
23
+ /**
24
+ * Monotonic HITL-cycle index within this execution: 0 on the first invocation,
25
+ * then the workflow's approvalCycle on each reinvocation. The Cursor producer
26
+ * mints its deterministic file-review change-set id ({@code executionId:turnSeq})
27
+ * from it. Absent on the legacy positional wire shape (defaults to 0).
28
+ */
29
+ readonly turn_seq?: number;
30
+ }
31
+ export interface NormalizedActivityInput {
32
+ readonly executionId: string;
33
+ readonly threadId: string;
34
+ /** HITL-cycle index for this invocation; 0 on the first turn / legacy wire shape. */
35
+ readonly turnSeq: number;
36
+ }
37
+ /**
38
+ * Normalizes either the new typed object or the legacy positional args into the
39
+ * `{ executionId, threadId, turnSeq }` the inner activity path consumes.
40
+ * `thread_id` is empty on a first invocation (new harness state) and `turn_seq`
41
+ * defaults to 0 (first turn, or the legacy positional shape that never carried it).
42
+ */
43
+ export declare function normalizeActivityInput(arg0: ExecuteActivityInput | string | undefined, arg1?: string): NormalizedActivityInput;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Normalizes either the new typed object or the legacy positional args into the
3
+ * `{ executionId, threadId, turnSeq }` the inner activity path consumes.
4
+ * `thread_id` is empty on a first invocation (new harness state) and `turn_seq`
5
+ * defaults to 0 (first turn, or the legacy positional shape that never carried it).
6
+ */
7
+ export function normalizeActivityInput(arg0, arg1) {
8
+ if (arg0 !== null && typeof arg0 === "object") {
9
+ return {
10
+ executionId: arg0.execution_id ?? "",
11
+ threadId: arg0.thread_id ?? "",
12
+ turnSeq: arg0.turn_seq ?? 0,
13
+ };
14
+ }
15
+ return { executionId: arg0 ?? "", threadId: arg1 ?? "", turnSeq: 0 };
16
+ }
17
+ //# sourceMappingURL=activity-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-input.js","sourceRoot":"","sources":["../../src/shared/activity-input.ts"],"names":[],"mappings":"AAsCA;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAA+C,EAC/C,IAAa;IAEb,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9C,OAAO;YACL,WAAW,EAAE,IAAI,CAAC,YAAY,IAAI,EAAE;YACpC,QAAQ,EAAE,IAAI,CAAC,SAAS,IAAI,EAAE;YAC9B,OAAO,EAAE,IAAI,CAAC,QAAQ,IAAI,CAAC;SAC5B,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,IAAI,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;AACvE,CAAC"}
@@ -0,0 +1,19 @@
1
+ export interface ToolActionInput {
2
+ toolName: string;
3
+ mcpServerSlug?: string;
4
+ paths?: string[];
5
+ shellCommand?: string;
6
+ args?: Record<string, unknown>;
7
+ secretKeys?: string[];
8
+ workspaceRoot?: string;
9
+ }
10
+ export interface CanonicalToolAction {
11
+ toolName: string;
12
+ mcpServerSlug: string;
13
+ paths: string[];
14
+ shellCommand: string;
15
+ args: Record<string, unknown>;
16
+ }
17
+ export declare function canonicalizeToolAction(input: ToolActionInput): CanonicalToolAction;
18
+ export declare function canonicalToolActionJson(input: ToolActionInput): string;
19
+ export declare function canonicalJson(value: unknown): string;
@@ -0,0 +1,119 @@
1
+ // Deterministic canonicalization of a tool action into a byte-stable form.
2
+ // Domain: HITL approval. This is the cross-language contract the approval
3
+ // fingerprint (Phase 2) will hash; Phase 1 *defines and computes* it without
4
+ // hashing, so Go/Java/TS can be pinned to byte-identical output via the shared
5
+ // vector corpus (apis/testdata/hitl/canonicalization/).
6
+ //
7
+ // Why this exists: the March 2026 dedup bug was caused by hashing divergent
8
+ // representations of the same action (display args in one place, raw args in
9
+ // another). The fix is a single, explicit normalization pass — applied at ONE
10
+ // layer — that erases incidental differences (path separators, workspace
11
+ // location, shell whitespace, MCP slug case, secret values) before any hash.
12
+ import { createHash } from "node:crypto";
13
+ import { posix } from "node:path";
14
+ export function canonicalizeToolAction(input) {
15
+ return {
16
+ toolName: input.toolName.trim(),
17
+ // Slugs are case-insensitive identity; lowercase so "GitHub" == "github".
18
+ mcpServerSlug: (input.mcpServerSlug ?? "").trim().toLowerCase(),
19
+ paths: normalizePaths(input.paths ?? [], input.workspaceRoot),
20
+ shellCommand: normalizeShellCommand(input.shellCommand ?? ""),
21
+ args: redactSecrets(input.args ?? {}, new Set(input.secretKeys ?? [])),
22
+ };
23
+ }
24
+ // canonicalToolActionJson is the single entry point: normalize, then serialize
25
+ // to canonical JSON. The returned string is the byte-stable contract value.
26
+ export function canonicalToolActionJson(input) {
27
+ return canonicalJson(canonicalizeToolAction(input));
28
+ }
29
+ // canonicalJson serializes a value to RFC 8785-style canonical JSON: object keys
30
+ // sorted by UTF-16 code unit, no insignificant whitespace, UTF-8 output.
31
+ //
32
+ // The input domain is deliberately constrained to strings, booleans, null,
33
+ // integers, arrays, and plain objects — the shape of a normalized tool action.
34
+ // Non-integer numbers are rejected rather than implementing RFC 8785's full
35
+ // number-formatting algorithm, keeping this hand-rolled serializer small and
36
+ // provably cross-language without a third-party dependency. Revisit if the
37
+ // canonical domain ever needs floats.
38
+ export function canonicalJson(value) {
39
+ return serialize(value);
40
+ }
41
+ function serialize(v) {
42
+ if (v === null)
43
+ return "null";
44
+ switch (typeof v) {
45
+ case "boolean":
46
+ return v ? "true" : "false";
47
+ case "number":
48
+ if (!Number.isFinite(v))
49
+ throw new Error("canonicalJson: non-finite number");
50
+ if (!Number.isInteger(v)) {
51
+ throw new Error("canonicalJson: non-integer numbers are not part of the canonical contract");
52
+ }
53
+ return String(v);
54
+ case "string":
55
+ // JSON.stringify produces the same minimal escaping and raw UTF-8 for
56
+ // non-ASCII that RFC 8785 mandates for these inputs.
57
+ return JSON.stringify(v);
58
+ case "object":
59
+ if (Array.isArray(v))
60
+ return "[" + v.map(serialize).join(",") + "]";
61
+ return serializeObject(v);
62
+ default:
63
+ throw new Error(`canonicalJson: unsupported type ${typeof v}`);
64
+ }
65
+ }
66
+ function serializeObject(obj) {
67
+ // `undefined`-valued keys are dropped (they have no JSON representation);
68
+ // remaining keys are sorted by UTF-16 code unit, which is JS's default string
69
+ // ordering and matches RFC 8785.
70
+ const keys = Object.keys(obj)
71
+ .filter((k) => obj[k] !== undefined)
72
+ .sort(compareUtf16);
73
+ const parts = keys.map((k) => JSON.stringify(k) + ":" + serialize(obj[k]));
74
+ return "{" + parts.join(",") + "}";
75
+ }
76
+ function compareUtf16(a, b) {
77
+ return a < b ? -1 : a > b ? 1 : 0;
78
+ }
79
+ function normalizePaths(paths, workspaceRoot) {
80
+ return paths.map((p) => normalizeOnePath(p, workspaceRoot)).sort(compareUtf16);
81
+ }
82
+ function normalizeOnePath(p, workspaceRoot) {
83
+ // Separator-normalize to forward slashes first so Windows and POSIX agree.
84
+ let s = p.replace(/\\/g, "/");
85
+ if (workspaceRoot) {
86
+ const root = workspaceRoot.replace(/\\/g, "/");
87
+ if (s === root) {
88
+ s = "";
89
+ }
90
+ else if (s.startsWith(root + "/")) {
91
+ s = s.slice(root.length + 1);
92
+ }
93
+ }
94
+ // Collapse `.`/`..` segments deterministically. posix.normalize("") -> ".".
95
+ return s === "" ? "" : posix.normalize(s);
96
+ }
97
+ function normalizeShellCommand(cmd) {
98
+ // Collapse runs of whitespace to a single space and trim. The argument VALUE
99
+ // (the command) is what matters; incidental spacing is not identity.
100
+ return cmd.replace(/\s+/g, " ").trim();
101
+ }
102
+ function redactSecrets(args, secretKeys) {
103
+ if (secretKeys.size === 0)
104
+ return args;
105
+ const out = {};
106
+ for (const [k, v] of Object.entries(args)) {
107
+ out[k] = secretKeys.has(k) ? redactValue(v) : v;
108
+ }
109
+ return out;
110
+ }
111
+ function redactValue(v) {
112
+ // Redact-but-stable: a SHA-256 digest keeps the canonical form stable across
113
+ // runs without ever placing the secret in cleartext. This is NOT the approval
114
+ // fingerprint — that is an HMAC keyed on a Stigmer secret, introduced in
115
+ // Phase 2. This digest is unkeyed redaction only.
116
+ const material = typeof v === "string" ? v : canonicalJson(v);
117
+ return "sha256:" + createHash("sha256").update(material, "utf8").digest("hex");
118
+ }
119
+ //# sourceMappingURL=approval-canonicalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-canonicalize.js","sourceRoot":"","sources":["../../src/shared/approval-canonicalize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Approval fingerprint — the exact-match enforcement identity for the HITL Tool
3
+ * Execution Gateway (Phase 2).
4
+ *
5
+ * A fingerprint is `HMAC-SHA256(key, canonicalForm)` over a canonicalized tool
6
+ * action (see {@link file://./approval-canonicalize.ts}). It answers exactly one
7
+ * question at the moment of side effect: "is *this* action the one the user
8
+ * approved?" An approval is bound to the canonical identity of the action, not to
9
+ * the transient id of the proposing tool call, so a re-driven action that differs
10
+ * from what was approved is re-asked — never silently executed.
11
+ *
12
+ * Why HMAC and not a bare SHA-256 (binding canonical decision,
13
+ * design-decisions/approval-fingerprint-vs-march-rollback.md, Rule 4): the
14
+ * fingerprint is an authorization token, not a correlation key. Keying it under a
15
+ * Stigmer-held secret means a model (or a compromised workspace) cannot forge a
16
+ * value that the gateway will accept. In Phase 2 the fingerprint is
17
+ * recompute-and-compare at one trusted layer (no bearer token crosses a wire), so
18
+ * the anti-forgery property is forward-looking — it earns its keep when a lease
19
+ * later becomes a server-issued bearer token (Phase 7). We pay the small cost now
20
+ * to avoid a migration that re-keys every persisted approval later.
21
+ *
22
+ * Two fidelities share this one canonicalization core, because the two
23
+ * enforcement substrates differ (see the Phase-2 plan, "two enforcement
24
+ * substrates, not one"):
25
+ *
26
+ * - FULL ({@link computeApprovalFingerprint}) — HMAC over the full canonical
27
+ * action (tool + paths + shellCommand + args). Used by the in-process
28
+ * deep-agent gateway, where approve-time and execute-time observe the same
29
+ * arg shape (LangGraph checkpoint replay), so the action can be matched at
30
+ * full fidelity.
31
+ * - COARSE ({@link computeCoarseApprovalFingerprint}) — HMAC over
32
+ * (category, salient) only. Used by the out-of-process Cursor deny-oracle
33
+ * hook, whose stdin payload names the same action with a different taxonomy
34
+ * (`Write` vs `edit`, `file_path` vs `path`) and cannot reproduce the full
35
+ * args. The coarse projection is the documented, substrate-forced coarsening
36
+ * that lets the hook-side and stream-side fingerprints agree; it is the
37
+ * successor identity for execute-cursor's grant token.
38
+ *
39
+ * The fingerprint is enforcement-only and never a correlation key — correlation
40
+ * stays `approval_request_id` + `tool_call_id`.
41
+ */
42
+ import { type BinaryLike } from "node:crypto";
43
+ import { type ToolActionInput } from "./approval-canonicalize.js";
44
+ /**
45
+ * Version tag prefixed to every fingerprint. Bumping it is the migration lever
46
+ * if the canonical form or the MAC primitive ever changes: an old lease and a
47
+ * new computation will not compare equal, so a version skew re-asks (safe) rather
48
+ * than silently mismatching. Keep in lockstep with the Go/Java editions.
49
+ */
50
+ export declare const APPROVAL_FINGERPRINT_VERSION = "v1";
51
+ /** The HMAC key. Raw bytes (Buffer) in production; a UTF-8 string in tests. */
52
+ export type FingerprintKey = BinaryLike;
53
+ /**
54
+ * Full-fidelity fingerprint for the in-process deep-agent gateway. Distinct
55
+ * actions (different tool, paths, command, or args) yield distinct fingerprints;
56
+ * the same action is byte-stable across re-invocations.
57
+ */
58
+ export declare function computeApprovalFingerprint(key: FingerprintKey, input: ToolActionInput): string;
59
+ /**
60
+ * The substrate-coarsened identity of a tool action — the only fidelity the
61
+ * Cursor deny-oracle hook can reproduce from its stdin payload.
62
+ *
63
+ * Mirrors execute-cursor's `toolIdentity` so the two converge on one definition:
64
+ * - `tool` is the cross-taxonomy {@link toolApprovalCategory} (`write`/`delete`/
65
+ * `shell`) for gated built-ins, the tool name for MCP tools (whose name is
66
+ * stable across layers), or the trimmed tool name for non-gated built-ins
67
+ * (never lease-matched, so the fallback is harmless).
68
+ * - `salient` is the single resource the action targets (a normalized path or the
69
+ * shell command), reusing the full form's normalization so one rule governs
70
+ * both fidelities. Empty for MCP tools, which are matched by `tool` alone.
71
+ */
72
+ export interface CoarseToolIdentity {
73
+ tool: string;
74
+ mcpServerSlug: string;
75
+ salient: string;
76
+ }
77
+ export declare function coarseToolIdentity(input: ToolActionInput): CoarseToolIdentity;
78
+ /**
79
+ * Fingerprint an already-reduced {@link CoarseToolIdentity}. Split out from
80
+ * {@link computeCoarseApprovalFingerprint} so a substrate that has *already*
81
+ * reduced a tool call to its (tool, mcpServerSlug, salient) identity — the Cursor
82
+ * harness, whose hook and stream both key on a raw, un-normalized salient that
83
+ * the bash hook can reproduce without a workspace root — can fingerprint that
84
+ * exact identity through the one shared HMAC+canonical-JSON path, instead of
85
+ * re-deriving the salient via {@link canonicalizeToolAction} (which normalizes
86
+ * paths and would diverge from the hook's raw value).
87
+ */
88
+ export declare function fingerprintCoarseIdentity(key: FingerprintKey, identity: CoarseToolIdentity): string;
89
+ /**
90
+ * Coarse fingerprint for the out-of-process Cursor hook. By construction, two
91
+ * actions that name the same operation in different taxonomies (`Write` vs
92
+ * `edit`) over the same resource collapse to one fingerprint — this is what makes
93
+ * the hook-side (deny/grant) and stream-side (reconciliation) values agree.
94
+ */
95
+ export declare function computeCoarseApprovalFingerprint(key: FingerprintKey, input: ToolActionInput): string;
96
+ /**
97
+ * Derive the per-execution fingerprint key from a runner-held master secret.
98
+ *
99
+ * The key is scoped to one `execution_id`: stable across Temporal re-invocations
100
+ * of the same execution (the gateway approves on one invocation and enforces on
101
+ * the next), and isolated between executions so a fingerprint approved for one
102
+ * cannot be replayed against another. The master-secret source is wired when the
103
+ * gateway first consumes the fingerprint (Slices C/D); until then this is
104
+ * exercised only by tests against a fixed master secret.
105
+ */
106
+ export declare function deriveExecutionFingerprintKey(masterSecret: FingerprintKey, executionId: string): Buffer;