@stigmer/runner 3.10.0 → 3.11.1-dev.20260812192248

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 (355) hide show
  1. package/README.md +14 -1
  2. package/dist/.build-fingerprint +1 -1
  3. package/dist/activities/call-llm.js +9 -10
  4. package/dist/activities/call-llm.js.map +1 -1
  5. package/dist/activities/classify-tool-approvals.d.ts +2 -1
  6. package/dist/activities/classify-tool-approvals.js +28 -2
  7. package/dist/activities/classify-tool-approvals.js.map +1 -1
  8. package/dist/activities/discover-mcp-server.d.ts +39 -0
  9. package/dist/activities/discover-mcp-server.js +165 -28
  10. package/dist/activities/discover-mcp-server.js.map +1 -1
  11. package/dist/activities/emit-event.d.ts +14 -2
  12. package/dist/activities/emit-event.js +52 -17
  13. package/dist/activities/emit-event.js.map +1 -1
  14. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.d.ts +8 -0
  15. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js +1 -1
  16. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js.map +1 -1
  17. package/dist/activities/execute-cursor/approval-state.d.ts +28 -2
  18. package/dist/activities/execute-cursor/approval-state.js +7 -1
  19. package/dist/activities/execute-cursor/approval-state.js.map +1 -1
  20. package/dist/activities/execute-cursor/attachment-resolver.d.ts +14 -0
  21. package/dist/activities/execute-cursor/attachment-resolver.js +18 -4
  22. package/dist/activities/execute-cursor/attachment-resolver.js.map +1 -1
  23. package/dist/activities/execute-cursor/blueprint-resolver.d.ts +1 -9
  24. package/dist/activities/execute-cursor/blueprint-resolver.js +6 -22
  25. package/dist/activities/execute-cursor/blueprint-resolver.js.map +1 -1
  26. package/dist/activities/execute-cursor/env-resolver.js +3 -1
  27. package/dist/activities/execute-cursor/env-resolver.js.map +1 -1
  28. package/dist/activities/execute-cursor/error-classifier.d.ts +59 -3
  29. package/dist/activities/execute-cursor/error-classifier.js +115 -6
  30. package/dist/activities/execute-cursor/error-classifier.js.map +1 -1
  31. package/dist/activities/execute-cursor/extract-structured-output.d.ts +29 -0
  32. package/dist/activities/execute-cursor/extract-structured-output.js +58 -0
  33. package/dist/activities/execute-cursor/extract-structured-output.js.map +1 -0
  34. package/dist/activities/execute-cursor/hook-script.d.ts +14 -3
  35. package/dist/activities/execute-cursor/hook-script.js +72 -10
  36. package/dist/activities/execute-cursor/hook-script.js.map +1 -1
  37. package/dist/activities/execute-cursor/index.d.ts +51 -11
  38. package/dist/activities/execute-cursor/index.js +177 -93
  39. package/dist/activities/execute-cursor/index.js.map +1 -1
  40. package/dist/activities/execute-cursor/mcp-resolver.d.ts +24 -1
  41. package/dist/activities/execute-cursor/mcp-resolver.js +5 -2
  42. package/dist/activities/execute-cursor/mcp-resolver.js.map +1 -1
  43. package/dist/activities/execute-cursor/model-pricing-data.d.ts +2 -0
  44. package/dist/activities/execute-cursor/model-pricing-data.js +13 -3
  45. package/dist/activities/execute-cursor/model-pricing-data.js.map +1 -1
  46. package/dist/activities/execute-cursor/prompt-builder.d.ts +51 -4
  47. package/dist/activities/execute-cursor/prompt-builder.js +49 -7
  48. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  49. package/dist/activities/execute-cursor/turn-recovery.d.ts +52 -0
  50. package/dist/activities/execute-cursor/turn-recovery.js +193 -0
  51. package/dist/activities/execute-cursor/turn-recovery.js.map +1 -0
  52. package/dist/activities/execute-cursor/turn-stream.js +4 -1
  53. package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
  54. package/dist/activities/execute-deep-agent/attachment-injector.d.ts +18 -1
  55. package/dist/activities/execute-deep-agent/attachment-injector.js +68 -23
  56. package/dist/activities/execute-deep-agent/attachment-injector.js.map +1 -1
  57. package/dist/activities/execute-deep-agent/environment.js +3 -1
  58. package/dist/activities/execute-deep-agent/environment.js.map +1 -1
  59. package/dist/activities/execute-deep-agent/index.js +15 -0
  60. package/dist/activities/execute-deep-agent/index.js.map +1 -1
  61. package/dist/activities/execute-deep-agent/prompt-builder.d.ts +7 -7
  62. package/dist/activities/execute-deep-agent/prompt-builder.js +8 -2
  63. package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
  64. package/dist/activities/execute-deep-agent/setup.d.ts +10 -0
  65. package/dist/activities/execute-deep-agent/setup.js +65 -24
  66. package/dist/activities/execute-deep-agent/setup.js.map +1 -1
  67. package/dist/activities/execute-deep-agent/shell-env.d.ts +5 -1
  68. package/dist/activities/execute-deep-agent/shell-env.js +7 -9
  69. package/dist/activities/execute-deep-agent/shell-env.js.map +1 -1
  70. package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +18 -1
  71. package/dist/activities/execute-deep-agent/subagent-transformer.js +15 -2
  72. package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
  73. package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +27 -6
  74. package/dist/activities/execute-deep-agent/subagent-wiring.js +26 -5
  75. package/dist/activities/execute-deep-agent/subagent-wiring.js.map +1 -1
  76. package/dist/activities/hydrate-workflow-execution.js +8 -3
  77. package/dist/activities/hydrate-workflow-execution.js.map +1 -1
  78. package/dist/activities/run-command.d.ts +5 -2
  79. package/dist/activities/run-command.js +22 -10
  80. package/dist/activities/run-command.js.map +1 -1
  81. package/dist/activities/run-env.d.ts +40 -0
  82. package/dist/activities/run-env.js +66 -0
  83. package/dist/activities/run-env.js.map +1 -0
  84. package/dist/activities/workflow-event-activities.d.ts +28 -10
  85. package/dist/activities/workflow-event-activities.js +87 -58
  86. package/dist/activities/workflow-event-activities.js.map +1 -1
  87. package/dist/bootstrap.js +5 -0
  88. package/dist/bootstrap.js.map +1 -1
  89. package/dist/claimcheck/payload-codec.js +21 -1
  90. package/dist/claimcheck/payload-codec.js.map +1 -1
  91. package/dist/client/stigmer-client.d.ts +83 -21
  92. package/dist/client/stigmer-client.js +106 -29
  93. package/dist/client/stigmer-client.js.map +1 -1
  94. package/dist/encryption/config.d.ts +64 -0
  95. package/dist/encryption/config.js +108 -0
  96. package/dist/encryption/config.js.map +1 -0
  97. package/dist/encryption/index.d.ts +3 -0
  98. package/dist/encryption/index.js +3 -0
  99. package/dist/encryption/index.js.map +1 -0
  100. package/dist/encryption/payload-codec.d.ts +41 -0
  101. package/dist/encryption/payload-codec.js +130 -0
  102. package/dist/encryption/payload-codec.js.map +1 -0
  103. package/dist/middleware/index.d.ts +3 -0
  104. package/dist/middleware/index.js +7 -0
  105. package/dist/middleware/index.js.map +1 -1
  106. package/dist/middleware/path-normalization.d.ts +57 -0
  107. package/dist/middleware/path-normalization.js +109 -0
  108. package/dist/middleware/path-normalization.js.map +1 -0
  109. package/dist/middleware/types.d.ts +8 -0
  110. package/dist/payload-codecs.d.ts +17 -0
  111. package/dist/payload-codecs.js +42 -0
  112. package/dist/payload-codecs.js.map +1 -0
  113. package/dist/preflight.d.ts +31 -0
  114. package/dist/preflight.js +43 -0
  115. package/dist/preflight.js.map +1 -1
  116. package/dist/runner-manager.js +21 -17
  117. package/dist/runner-manager.js.map +1 -1
  118. package/dist/runner.js +11 -18
  119. package/dist/runner.js.map +1 -1
  120. package/dist/shared/approval-policy.d.ts +9 -3
  121. package/dist/shared/approval-policy.js +15 -6
  122. package/dist/shared/approval-policy.js.map +1 -1
  123. package/dist/shared/artifact-storage.d.ts +23 -1
  124. package/dist/shared/artifact-storage.js +51 -10
  125. package/dist/shared/artifact-storage.js.map +1 -1
  126. package/dist/shared/attachment-naming.d.ts +53 -0
  127. package/dist/shared/attachment-naming.js +59 -0
  128. package/dist/shared/attachment-naming.js.map +1 -0
  129. package/dist/shared/caller-identity.d.ts +23 -2
  130. package/dist/shared/caller-identity.js +36 -5
  131. package/dist/shared/caller-identity.js.map +1 -1
  132. package/dist/shared/channel-attachment.js +1 -0
  133. package/dist/shared/channel-attachment.js.map +1 -1
  134. package/dist/shared/checkpointer/http-saver.d.ts +26 -1
  135. package/dist/shared/checkpointer/http-saver.js +54 -8
  136. package/dist/shared/checkpointer/http-saver.js.map +1 -1
  137. package/dist/shared/conversation-attachment.js +1 -0
  138. package/dist/shared/conversation-attachment.js.map +1 -1
  139. package/dist/shared/conversation-catchup.d.ts +9 -2
  140. package/dist/shared/conversation-catchup.js +39 -6
  141. package/dist/shared/conversation-catchup.js.map +1 -1
  142. package/dist/shared/datastore-attachment.d.ts +50 -7
  143. package/dist/shared/datastore-attachment.js +93 -11
  144. package/dist/shared/datastore-attachment.js.map +1 -1
  145. package/dist/shared/grpc-retry.d.ts +5 -1
  146. package/dist/shared/grpc-retry.js +5 -1
  147. package/dist/shared/grpc-retry.js.map +1 -1
  148. package/dist/shared/http-retry.d.ts +85 -0
  149. package/dist/shared/http-retry.js +101 -0
  150. package/dist/shared/http-retry.js.map +1 -0
  151. package/dist/shared/llm-backend.d.ts +275 -0
  152. package/dist/shared/llm-backend.js +425 -0
  153. package/dist/shared/llm-backend.js.map +1 -0
  154. package/dist/shared/llm-proxy.d.ts +8 -0
  155. package/dist/shared/llm-proxy.js +15 -0
  156. package/dist/shared/llm-proxy.js.map +1 -1
  157. package/dist/shared/mcp-enabled-tools.d.ts +57 -0
  158. package/dist/shared/mcp-enabled-tools.js +86 -0
  159. package/dist/shared/mcp-enabled-tools.js.map +1 -0
  160. package/dist/shared/mcp-manager.d.ts +11 -5
  161. package/dist/shared/mcp-manager.js +47 -8
  162. package/dist/shared/mcp-manager.js.map +1 -1
  163. package/dist/shared/mcp-resolver.d.ts +39 -2
  164. package/dist/shared/mcp-resolver.js +38 -2
  165. package/dist/shared/mcp-resolver.js.map +1 -1
  166. package/dist/shared/mcp-schema-sanitizer.d.ts +70 -0
  167. package/dist/shared/mcp-schema-sanitizer.js +197 -0
  168. package/dist/shared/mcp-schema-sanitizer.js.map +1 -0
  169. package/dist/shared/model-client.d.ts +18 -5
  170. package/dist/shared/model-client.js +149 -18
  171. package/dist/shared/model-client.js.map +1 -1
  172. package/dist/shared/model-error.js +198 -5
  173. package/dist/shared/model-error.js.map +1 -1
  174. package/dist/shared/model-pricing-data.d.ts +2 -0
  175. package/dist/shared/model-pricing-data.js +13 -3
  176. package/dist/shared/model-pricing-data.js.map +1 -1
  177. package/dist/shared/model-registry.js +3 -2
  178. package/dist/shared/model-registry.js.map +1 -1
  179. package/dist/shared/plan-mode-permissions.d.ts +33 -0
  180. package/dist/shared/plan-mode-permissions.js +35 -0
  181. package/dist/shared/plan-mode-permissions.js.map +1 -0
  182. package/dist/shared/registry-endpoint.d.ts +20 -0
  183. package/dist/shared/registry-endpoint.js +25 -0
  184. package/dist/shared/registry-endpoint.js.map +1 -1
  185. package/dist/shared/runner-credential-keys.d.ts +24 -0
  186. package/dist/shared/runner-credential-keys.js +47 -0
  187. package/dist/shared/runner-credential-keys.js.map +1 -0
  188. package/dist/worker.d.ts +2 -1
  189. package/dist/worker.js +2 -4
  190. package/dist/worker.js.map +1 -1
  191. package/dist/workflow-engine/resolve.d.ts +19 -1
  192. package/dist/workflow-engine/resolve.js +37 -2
  193. package/dist/workflow-engine/resolve.js.map +1 -1
  194. package/dist/workflow-engine/types.d.ts +18 -0
  195. package/dist/workflow-engine/types.js.map +1 -1
  196. package/dist/workflows/call-agent-orchestrator.d.ts +9 -0
  197. package/dist/workflows/call-agent-orchestrator.js +1 -0
  198. package/dist/workflows/call-agent-orchestrator.js.map +1 -1
  199. package/dist/workflows/connect-mcp-server.js +9 -0
  200. package/dist/workflows/connect-mcp-server.js.map +1 -1
  201. package/dist/workflows/engine-core.js +23 -2
  202. package/dist/workflows/engine-core.js.map +1 -1
  203. package/dist/workflows/execute-from-execution.d.ts +1 -1
  204. package/dist/workflows/execute-from-execution.js +11 -1
  205. package/dist/workflows/execute-from-execution.js.map +1 -1
  206. package/dist/workflows/types.d.ts +8 -0
  207. package/package.json +9 -4
  208. package/src/__test-utils__/__tests__/vitest-global-setup.test.ts +37 -0
  209. package/src/__test-utils__/vitest-global-setup.ts +50 -0
  210. package/src/__tests__/bootstrap.test.ts +43 -0
  211. package/src/__tests__/claimcheck-codec.test.ts +36 -0
  212. package/src/__tests__/encryption-codec.test.ts +287 -0
  213. package/src/__tests__/fixtures/encrypted-payload-fixture.json +15 -0
  214. package/src/__tests__/history-encryption-e2e.test.ts +243 -0
  215. package/src/__tests__/preflight.test.ts +65 -2
  216. package/src/activities/__tests__/call-llm.test.ts +75 -0
  217. package/src/activities/__tests__/classify-tool-approvals.test.ts +117 -1
  218. package/src/activities/__tests__/discover-mcp-server.hang.test.ts +103 -0
  219. package/src/activities/__tests__/discover-mcp-server.test.ts +242 -1
  220. package/src/activities/__tests__/error-classifier.test.ts +94 -2
  221. package/src/activities/__tests__/run-command.test.ts +221 -0
  222. package/src/activities/__tests__/workflow-event-activities.test.ts +107 -8
  223. package/src/activities/call-llm.ts +9 -16
  224. package/src/activities/classify-tool-approvals.ts +34 -4
  225. package/src/activities/discover-mcp-server.ts +203 -31
  226. package/src/activities/emit-event.ts +65 -21
  227. package/src/activities/execute-cursor/__test-utils__/cursor-hook-harness.ts +9 -0
  228. package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +14 -0
  229. package/src/activities/execute-cursor/__tests__/attachment-resolver.test.ts +53 -0
  230. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +151 -16
  231. package/src/activities/execute-cursor/__tests__/error-classifier-extraction.test.ts +208 -0
  232. package/src/activities/execute-cursor/__tests__/extract-structured-output.test.ts +120 -0
  233. package/src/activities/execute-cursor/__tests__/hook-script.test.ts +93 -0
  234. package/src/activities/execute-cursor/__tests__/mcp-resolver.test.ts +125 -0
  235. package/src/activities/execute-cursor/__tests__/model-pricing.test.ts +62 -1
  236. package/src/activities/execute-cursor/__tests__/prompt-builder-delegation.test.ts +1 -1
  237. package/src/activities/execute-cursor/__tests__/turn-recovery.test.ts +160 -0
  238. package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +13 -0
  239. package/src/activities/execute-cursor/approval-state.ts +30 -1
  240. package/src/activities/execute-cursor/attachment-resolver.ts +31 -3
  241. package/src/activities/execute-cursor/blueprint-resolver.ts +7 -27
  242. package/src/activities/execute-cursor/env-resolver.ts +3 -1
  243. package/src/activities/execute-cursor/error-classifier.ts +131 -7
  244. package/src/activities/execute-cursor/extract-structured-output.ts +72 -0
  245. package/src/activities/execute-cursor/hook-script.ts +74 -10
  246. package/src/activities/execute-cursor/index.ts +209 -109
  247. package/src/activities/execute-cursor/mcp-resolver.ts +36 -2
  248. package/src/activities/execute-cursor/model-pricing-data.ts +22 -3
  249. package/src/activities/execute-cursor/prompt-builder.ts +85 -9
  250. package/src/activities/execute-cursor/turn-recovery.ts +208 -0
  251. package/src/activities/execute-cursor/turn-stream.ts +5 -2
  252. package/src/activities/execute-deep-agent/__tests__/attachment-injector.test.ts +110 -8
  253. package/src/activities/execute-deep-agent/__tests__/datastore-degradation.test.ts +104 -0
  254. package/src/activities/execute-deep-agent/__tests__/hitl-reject.test.ts +2 -0
  255. package/src/activities/execute-deep-agent/__tests__/hitl-resume-approve-all.test.ts +1 -0
  256. package/src/activities/execute-deep-agent/__tests__/hitl-resume-history.test.ts +1 -0
  257. package/src/activities/execute-deep-agent/__tests__/plan-mode-path-normalization.test.ts +174 -0
  258. package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +34 -5
  259. package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +1 -0
  260. package/src/activities/execute-deep-agent/__tests__/shell-env.test.ts +24 -10
  261. package/src/activities/execute-deep-agent/__tests__/subagent-plan-mode-permissions.test.ts +178 -0
  262. package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +12 -7
  263. package/src/activities/execute-deep-agent/attachment-injector.ts +94 -30
  264. package/src/activities/execute-deep-agent/environment.ts +3 -1
  265. package/src/activities/execute-deep-agent/index.ts +20 -0
  266. package/src/activities/execute-deep-agent/prompt-builder.ts +20 -10
  267. package/src/activities/execute-deep-agent/setup.ts +85 -29
  268. package/src/activities/execute-deep-agent/shell-env.ts +8 -9
  269. package/src/activities/execute-deep-agent/subagent-transformer.ts +30 -2
  270. package/src/activities/execute-deep-agent/subagent-wiring.ts +39 -6
  271. package/src/activities/hydrate-workflow-execution.ts +8 -3
  272. package/src/activities/run-command.ts +25 -12
  273. package/src/activities/run-env.ts +79 -0
  274. package/src/activities/workflow-event-activities.ts +96 -69
  275. package/src/bootstrap.ts +5 -0
  276. package/src/claimcheck/payload-codec.ts +33 -1
  277. package/src/client/__tests__/stigmer-client.test.ts +110 -11
  278. package/src/client/stigmer-client.ts +150 -37
  279. package/src/encryption/config.ts +155 -0
  280. package/src/encryption/index.ts +3 -0
  281. package/src/encryption/payload-codec.ts +152 -0
  282. package/src/middleware/__tests__/path-normalization.test.ts +140 -0
  283. package/src/middleware/index.ts +8 -0
  284. package/src/middleware/path-normalization.ts +125 -0
  285. package/src/middleware/types.ts +11 -0
  286. package/src/payload-codecs.ts +62 -0
  287. package/src/preflight.ts +45 -0
  288. package/src/runner-manager.ts +26 -26
  289. package/src/runner.ts +12 -27
  290. package/src/shared/__tests__/approval-policy.test.ts +82 -39
  291. package/src/shared/__tests__/artifact-storage.test.ts +145 -2
  292. package/src/shared/__tests__/attachment-naming.test.ts +159 -0
  293. package/src/shared/__tests__/bedrock-adapter.test.ts +213 -0
  294. package/src/shared/__tests__/bedrock-seam.test.ts +390 -0
  295. package/src/shared/__tests__/caller-identity.test.ts +25 -0
  296. package/src/shared/__tests__/channel-attachment.test.ts +1 -1
  297. package/src/shared/__tests__/connect-backfill.test.ts +1 -0
  298. package/src/shared/__tests__/conversation-attachment.test.ts +1 -1
  299. package/src/shared/__tests__/conversation-catchup.test.ts +24 -0
  300. package/src/shared/__tests__/datastore-attachment.test.ts +129 -1
  301. package/src/shared/__tests__/foundry-adapter.test.ts +276 -0
  302. package/src/shared/__tests__/foundry-seam.test.ts +482 -0
  303. package/src/shared/__tests__/http-retry.test.ts +68 -0
  304. package/src/shared/__tests__/llm-backend.test.ts +616 -0
  305. package/src/shared/__tests__/mcp-enabled-tools.test.ts +86 -0
  306. package/src/shared/__tests__/mcp-manager.test.ts +137 -15
  307. package/src/shared/__tests__/mcp-resolver.test.ts +146 -3
  308. package/src/shared/__tests__/mcp-schema-sanitizer.test.ts +267 -0
  309. package/src/shared/__tests__/model-client.test.ts +200 -0
  310. package/src/shared/__tests__/model-error.test.ts +289 -1
  311. package/src/shared/__tests__/model-pricing.test.ts +62 -2
  312. package/src/shared/__tests__/model-registry.test.ts +22 -0
  313. package/src/shared/__tests__/synthesized-attachment.test.ts +1 -0
  314. package/src/shared/__tests__/vertex-adapter.test.ts +169 -0
  315. package/src/shared/__tests__/vertex-seam.test.ts +295 -0
  316. package/src/shared/approval-policy.ts +14 -7
  317. package/src/shared/artifact-storage.ts +75 -10
  318. package/src/shared/attachment-naming.ts +78 -0
  319. package/src/shared/caller-identity.ts +40 -5
  320. package/src/shared/channel-attachment.ts +1 -0
  321. package/src/shared/checkpointer/__tests__/http-saver.test.ts +196 -1
  322. package/src/shared/checkpointer/http-saver.ts +71 -8
  323. package/src/shared/conversation-attachment.ts +1 -0
  324. package/src/shared/conversation-catchup.ts +39 -6
  325. package/src/shared/datastore-attachment.ts +106 -11
  326. package/src/shared/grpc-retry.ts +5 -1
  327. package/src/shared/http-retry.ts +139 -0
  328. package/src/shared/llm-backend.ts +544 -0
  329. package/src/shared/llm-proxy.ts +15 -0
  330. package/src/shared/mcp-enabled-tools.ts +105 -0
  331. package/src/shared/mcp-manager.ts +56 -8
  332. package/src/shared/mcp-resolver.ts +73 -2
  333. package/src/shared/mcp-schema-sanitizer.ts +224 -0
  334. package/src/shared/model-client.ts +179 -19
  335. package/src/shared/model-error.ts +222 -4
  336. package/src/shared/model-pricing-data.ts +22 -3
  337. package/src/shared/model-registry.ts +7 -2
  338. package/src/shared/plan-mode-permissions.ts +37 -0
  339. package/src/shared/registry-endpoint.ts +27 -0
  340. package/src/shared/runner-credential-keys.ts +46 -0
  341. package/src/worker.ts +4 -5
  342. package/src/workflow-engine/__tests__/tasks/emit-event.test.ts +127 -49
  343. package/src/workflow-engine/resolve.ts +48 -2
  344. package/src/workflow-engine/types.ts +18 -0
  345. package/src/workflows/__tests__/connect-mcp-server.test.ts +25 -0
  346. package/src/workflows/__tests__/execute-serverless-workflow.test.ts +68 -2
  347. package/src/workflows/call-agent-orchestrator.ts +10 -0
  348. package/src/workflows/connect-mcp-server.ts +9 -0
  349. package/src/workflows/engine-core.ts +23 -2
  350. package/src/workflows/execute-from-execution.ts +12 -2
  351. package/src/workflows/types.ts +8 -0
  352. package/dist/activities/execute-cursor/mcp-config.d.ts +0 -30
  353. package/dist/activities/execute-cursor/mcp-config.js +0 -39
  354. package/dist/activities/execute-cursor/mcp-config.js.map +0 -1
  355. package/src/activities/execute-cursor/mcp-config.ts +0 -66
@@ -15,12 +15,15 @@
15
15
  * no approval gate — see deepagents-profiles.ts for the suppression half)
16
16
  * - Sub-agent backends are shell-capable outside plan mode (issue #248), mirroring
17
17
  * the parent's backend selection in setup.ts
18
+ * - Sub-agent graphs carry the parent's filesystem permissions explicitly
19
+ * (issue #255): pre-built CompiledSubAgents never inherit them, so plan
20
+ * mode's deny-all-writes rule is baked into each graph at compile time
18
21
  * - Invalid configurations are logged and skipped (graceful degradation)
19
22
  * - Empty subagent list returns null (no subagents configured)
20
23
  */
21
24
 
22
25
  import { createDeepAgent, FilesystemBackend, LocalShellBackend, DEFAULT_GENERAL_PURPOSE_DESCRIPTION, DEFAULT_SUBAGENT_PROMPT } from "deepagents";
23
- import type { CompiledSubAgent } from "deepagents";
26
+ import type { CompiledSubAgent, FilesystemPermission } from "deepagents";
24
27
  import type { StructuredTool } from "@langchain/core/tools";
25
28
  import type { RunnableConfig } from "@langchain/core/runnables";
26
29
  import type { BaseChatModel } from "@langchain/core/language_models/chat_models";
@@ -180,6 +183,18 @@ export interface SubagentTransformOptions {
180
183
  * backends, exactly like the parent's backend selection.
181
184
  */
182
185
  readonly shellEnv?: Record<string, string>;
186
+ /**
187
+ * Filesystem permission rules baked into each compiled sub-agent graph,
188
+ * inherited from the parent's rules in setup.ts (plan mode's deny-all-writes
189
+ * today). Required because deepagents' parent-permission inheritance covers
190
+ * only spec-style sub-agents — pre-built CompiledSubAgents bypass it, so
191
+ * without this a plan-mode sub-agent could still write (issue #255).
192
+ *
193
+ * Must not be combined with `shellEnv`: deepagents rejects permissions on an
194
+ * execution-capable backend (see the cas-capture-backend.ts header). Plan
195
+ * mode guarantees that by construction — it is the mode that clears shellEnv.
196
+ */
197
+ readonly permissions?: FilesystemPermission[];
183
198
  }
184
199
 
185
200
  // =========================================================================
@@ -525,6 +540,8 @@ export async function compileSubagents(
525
540
  readonly modelFactory?: (modelName: string) => Promise<BaseChatModel>;
526
541
  /** Shell env for `execute`; see {@link SubagentTransformOptions.shellEnv}. */
527
542
  readonly shellEnv?: Record<string, string>;
543
+ /** Per-graph filesystem rules; see {@link SubagentTransformOptions.permissions}. */
544
+ readonly permissions?: FilesystemPermission[];
528
545
  },
529
546
  ): Promise<CompiledSubAgent[]> {
530
547
  if (transformed.length === 0) return [];
@@ -537,11 +554,17 @@ export async function compileSubagents(
537
554
  // Structural coupling (DD-19): a sub-agent gate flows gitignored writes into
538
555
  // CAS iff a CAS observer backs that sub-agent's filesystem backend. Deriving
539
556
  // both from the same `casObserver` makes "unobserved unreviewable bytes"
540
- // impossible by construction.
557
+ // impossible by construction. Same idiom for path normalization
558
+ // (issue #429): derived from the same `permissions` baked into the graph
559
+ // below, so a rule-bearing graph always carries the shim that keeps
560
+ // prompt-compliant relative paths from dying in rule validation.
541
561
  const middleware = buildSubAgentMiddleware({
542
562
  costCap: opts.costCap,
543
563
  approvalGate: opts.approvalGate,
544
564
  captureIgnored: !!opts.casObserver,
565
+ ...(opts.permissions?.length
566
+ ? { pathNormalization: { rootDir: opts.workspaceRootDir } }
567
+ : {}),
545
568
  });
546
569
 
547
570
  const modelName = spec.model ?? opts.parentModelName;
@@ -560,6 +583,9 @@ export async function compileSubagents(
560
583
  tools: spec.tools.length > 0 ? spec.tools : undefined,
561
584
  middleware: middleware as unknown[],
562
585
  backend,
586
+ // Enforced inside this graph's own filesystem tools — and inherited by
587
+ // any spec-style sub-agent deepagents auto-injects one level deeper.
588
+ ...(opts.permissions ? { permissions: opts.permissions } : {}),
563
589
  } as Parameters<typeof createDeepAgent>[0]);
564
590
 
565
591
  const gatedRunnable = gate.wrapRunnable(
@@ -623,6 +649,7 @@ export async function transformAndCompileSubagents(
623
649
  costCap,
624
650
  modelFactory,
625
651
  shellEnv,
652
+ permissions,
626
653
  } = options;
627
654
 
628
655
  if (subAgents.length === 0 && !workspaceBackend.rootDir) {
@@ -743,6 +770,7 @@ export async function transformAndCompileSubagents(
743
770
  casObserver,
744
771
  modelFactory,
745
772
  shellEnv,
773
+ permissions,
746
774
  });
747
775
 
748
776
  if (compiled.length === 0) {
@@ -2,6 +2,12 @@
2
2
  * Sub-agent middleware composition for ExecuteDeepAgent.
3
3
  *
4
4
  * Each sub-agent gets its own middleware stack with:
5
+ * - Path normalization (issue #429), FIRST and only on permission-rule-
6
+ * bearing graphs (plan mode) — workspace-relative paths are rewritten to
7
+ * workspace-absolute before deepagents' permission validation refuses
8
+ * them, exactly as on the parent. `compileSubagents` derives it from the
9
+ * same `permissions` option it bakes into the graph, keeping the rules
10
+ * and their normalization shim coupled.
5
11
  * - Fresh loop detection (independent cycle tracking)
6
12
  * - Fresh tool truncation (same limits as parent)
7
13
  * - Periodic execution budget (interval=30, max=4 advisories)
@@ -9,11 +15,16 @@
9
15
  * bypassed) — installed only when the parent itself is gated
10
16
  * (`approvalGate` present; absent under auto-approve-all)
11
17
  * - Shared cost cap view (parent's budget, no reset on sub-agent start)
18
+ * - Error hints (issue #255): a thrown tool error becomes a recoverable
19
+ * ToolMessage exactly as on the parent. Without it, any tool throw — a
20
+ * plan-mode permission denial, an MCP hiccup — propagated out of the
21
+ * sub-agent graph and killed the whole delegated task, losing all its
22
+ * accumulated work, where the parent's identical error is one failed
23
+ * tool round the model adapts to.
12
24
  *
13
25
  * The sub-agent middleware stack does NOT include:
14
26
  * - Graceful stop (parent handles STOP signal propagation)
15
27
  * - OTel spans (parent's OTel context propagates automatically)
16
- * - Error hints (applied at tool level, not sub-agent level)
17
28
  *
18
29
  * Approval-gate note: the gate is what *creates* the LangGraph `interrupt()`.
19
30
  * A sub-agent's interrupt does surface at the parent checkpoint and resumes
@@ -22,8 +33,13 @@
22
33
  * the live HITL bypass this wiring closes.
23
34
  */
24
35
 
25
- import type { StigmerMiddleware, ToolTruncationConfig } from "../../middleware/types.js";
36
+ import type {
37
+ StigmerMiddleware,
38
+ ToolTruncationConfig,
39
+ PathNormalizationConfig,
40
+ } from "../../middleware/types.js";
26
41
  import type { CostCapMiddleware } from "../../middleware/index.js";
42
+ import { createPathNormalizationMiddleware } from "../../middleware/path-normalization.js";
27
43
  import { createLoopDetectionMiddleware } from "../../middleware/loop-detection.js";
28
44
  import { createToolTruncationMiddleware } from "../../middleware/tool-truncation.js";
29
45
  import { createExecutionBudgetMiddleware } from "../../middleware/execution-budget.js";
@@ -31,6 +47,7 @@ import {
31
47
  createApprovalGateMiddleware,
32
48
  type ApprovalGateConfig,
33
49
  } from "../../middleware/approval-gate.js";
50
+ import { createErrorHintsMiddleware } from "../../middleware/error-hints.js";
34
51
 
35
52
  const SUB_AGENT_ADVISORY_INTERVAL = 30;
36
53
  const SUB_AGENT_MAX_ADVISORIES = 4;
@@ -53,22 +70,36 @@ export interface SubAgentMiddlewareOptions {
53
70
  * unobserved backend would apply unreviewable bytes.
54
71
  */
55
72
  readonly captureIgnored?: boolean;
73
+ /**
74
+ * Workspace-relative path normalization (issue #429). Present iff this
75
+ * sub-agent's graph carries filesystem permission rules — the caller
76
+ * derives it from the same `permissions` value it bakes into the graph.
77
+ */
78
+ readonly pathNormalization?: PathNormalizationConfig;
56
79
  }
57
80
 
58
81
  /**
59
82
  * Build the middleware stack for a single sub-agent.
60
83
  *
61
84
  * Returns an ordered array mirroring the parent composition:
62
- * loop detection → execution budget (periodic) → tool truncation →
63
- * [approval gate] → cost cap view. The gate sits before the cost-cap view so an
64
- * approval pause happens before budget accounting, matching the parent order
65
- * (…→ truncation graceful-stop approval gate cost cap …).
85
+ * [path normalization] → loop detection → execution budget (periodic) →
86
+ * tool truncation → [approval gate] → cost cap view error hints.
87
+ * Normalization is outermost so everything downstream observes canonical
88
+ * workspace-absolute paths (matching the parent). The gate sits before the
89
+ * cost-cap view so an approval pause happens before budget accounting, and
90
+ * error hints come after the gate — both matching the parent order
91
+ * (…→ truncation → graceful-stop → approval gate → cost cap → error hints …),
92
+ * which keeps the gate's HITL interrupt outside the hints' try/catch.
66
93
  */
67
94
  export function buildSubAgentMiddleware(
68
95
  options: SubAgentMiddlewareOptions = {},
69
96
  ): StigmerMiddleware[] {
70
97
  const stack: StigmerMiddleware[] = [];
71
98
 
99
+ if (options.pathNormalization) {
100
+ stack.push(createPathNormalizationMiddleware(options.pathNormalization));
101
+ }
102
+
72
103
  stack.push(createLoopDetectionMiddleware({ enabled: true }));
73
104
 
74
105
  stack.push(createExecutionBudgetMiddleware({
@@ -99,5 +130,7 @@ export function buildSubAgentMiddleware(
99
130
  stack.push(options.costCap.forSubAgent());
100
131
  }
101
132
 
133
+ stack.push(createErrorHintsMiddleware());
134
+
102
135
  return stack;
103
136
  }
@@ -265,9 +265,14 @@ async function fetchAndFlattenEnv(
265
265
  client: StigmerClient,
266
266
  executionId: string,
267
267
  ): Promise<Record<string, unknown>> {
268
- // A desktop runner exchanges its bootstrap credential for a token scoped to
269
- // this workflow execution, so cloud's decrypt gate binds the read (#156).
270
- // No-op for cloud sandbox and OSS runners.
268
+ // The runner acquires a token scoped to this workflow execution so the
269
+ // server's decrypt gate binds the read: a desktop runner exchanges its
270
+ // bootstrap credential (#156, hard error on failure — the bootstrap
271
+ // credential no longer decrypts since stigmer-cloud#218, so proceeding
272
+ // would hydrate redacted placeholders), and an OSS runner asks the
273
+ // credential-less best-effort exchange (oss#535 — the OSS server redacts
274
+ // EC reads by default and mints execution-scoped tokens). No-op for cloud
275
+ // sandbox runners, whose ambient credential is already scoped.
271
276
  const scopedToken = await client.acquireScopedRunnerToken({
272
277
  workflowExecutionId: executionId,
273
278
  });
@@ -5,8 +5,11 @@
5
5
  * - RunScript: writes inline code to a temp file, executes via node/python
6
6
  * - RunShell: executes a shell command directly
7
7
  *
8
- * Both resolve runtime placeholders (JIT secrets) before execution
9
- * and capture stdout as the activity result.
8
+ * The child environment follows the declare-to-receive contract in
9
+ * run-env.ts: a minimal base plus the task's declared `environment`,
10
+ * with runtime placeholders (JIT secrets) resolved here in the activity
11
+ * so secret values never enter Temporal history. Both activities capture
12
+ * stdout as the activity result.
10
13
  */
11
14
 
12
15
  import { execFile, exec } from "node:child_process";
@@ -16,7 +19,9 @@ import { join } from "node:path";
16
19
  import { promisify } from "node:util";
17
20
  import { ApplicationFailure } from "@temporalio/activity";
18
21
  import type { RunCommandConfig } from "../workflow-engine/types.js";
22
+ import { RuntimePlaceholderResolutionError } from "../workflow-engine/resolve.js";
19
23
  import { startHeartbeat } from "../shared/heartbeat.js";
24
+ import { buildRunEnv } from "./run-env.js";
20
25
 
21
26
  const execFileAsync = promisify(execFile);
22
27
  const execAsync = promisify(exec);
@@ -49,7 +54,7 @@ async function runScriptImpl(config: RunCommandConfig): Promise<unknown> {
49
54
 
50
55
  const language = config.language!;
51
56
  const code = config.code!;
52
- const env = buildEnv(config.environment);
57
+ const env = buildTaskEnv(config);
53
58
 
54
59
  const ext = language === "js" ? ".js" : ".py";
55
60
  const interpreter = language === "js" ? "node" : "python3";
@@ -94,7 +99,7 @@ async function runShellImpl(config: RunCommandConfig): Promise<unknown> {
94
99
  const fullCommand = args.length > 0
95
100
  ? `${command} ${args.join(" ")}`
96
101
  : command;
97
- const env = buildEnv(config.environment);
102
+ const env = buildTaskEnv(config);
98
103
 
99
104
  try {
100
105
  const { stdout } = await execAsync(fullCommand, {
@@ -116,16 +121,24 @@ async function runShellImpl(config: RunCommandConfig): Promise<unknown> {
116
121
  }
117
122
  }
118
123
 
119
- function buildEnv(
120
- taskEnv?: Record<string, string>,
121
- ): Record<string, string | undefined> {
122
- const base = { ...process.env };
123
- if (taskEnv) {
124
- for (const [k, v] of Object.entries(taskEnv)) {
125
- base[k] = v;
124
+ /**
125
+ * Build the child env per the run-env.ts contract, translating a missing
126
+ * placeholder key into a non-retryable failure — retrying cannot conjure
127
+ * a variable the workflow's runtime env does not have.
128
+ */
129
+ function buildTaskEnv(config: RunCommandConfig): Record<string, string> {
130
+ try {
131
+ return buildRunEnv(config.environment, config.runtimeEnv);
132
+ } catch (err: unknown) {
133
+ if (err instanceof RuntimePlaceholderResolutionError) {
134
+ throw ApplicationFailure.nonRetryable(
135
+ err.message,
136
+ "RUN_ENV_UNRESOLVED_PLACEHOLDER",
137
+ { variable: err.variableName },
138
+ );
126
139
  }
140
+ throw err;
127
141
  }
128
- return base;
129
142
  }
130
143
 
131
144
  function buildArgsList(args: unknown): string[] {
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Environment contract for the workflow `run` task (shell and script modes).
3
+ *
4
+ * Declare-to-receive, the same rule the stdio MCP contract adopted after
5
+ * #256 (PR #383): the child process sees ONLY
6
+ *
7
+ * 1. a minimal base copied from the runner process
8
+ * ({@link RUN_ENV_BASE_KEYS} — the six variables the MCP SDK pins),
9
+ * 2. the task's declared `environment` map, with `${.secrets.KEY}` /
10
+ * `${.env_vars.KEY}` placeholders resolved just-in-time from the
11
+ * workflow's runtime env. Resolution happens here in the activity,
12
+ * never in the deterministic workflow phase, so secret values stay
13
+ * out of Temporal history.
14
+ *
15
+ * Runner credentials (STIGMER_TOKEN, the HITL secret, provider keys) are
16
+ * structurally absent rather than denylisted — a workflow-authored
17
+ * `printenv` cannot read what was never passed (oss#384). A missing
18
+ * placeholder key fails loudly: running a command with a silently-empty
19
+ * credential produces cryptic downstream failures.
20
+ *
21
+ * Placeholders resolve only in declared environment VALUES, never in
22
+ * `command` / `code` strings — argv is visible to `ps` on the host, so
23
+ * the environment is the sanctioned channel for secrets.
24
+ */
25
+
26
+ import { resolveRuntimePlaceholdersStrict } from "../workflow-engine/resolve.js";
27
+
28
+ /**
29
+ * Base variables copied from the runner process when present — the same
30
+ * six the MCP SDK provides to stdio servers, so "undeclared subprocess
31
+ * environment" has one platform-wide answer. `PATH` keeps interpreters
32
+ * and tools findable; the rest keep shells and language runtimes sane.
33
+ */
34
+ export const RUN_ENV_BASE_KEYS: readonly string[] = [
35
+ "HOME",
36
+ "LOGNAME",
37
+ "PATH",
38
+ "SHELL",
39
+ "TERM",
40
+ "USER",
41
+ ];
42
+
43
+ /**
44
+ * Build the environment for a run task's child process: minimal base +
45
+ * declared overlay with strict placeholder resolution (declared wins on
46
+ * conflict with the base).
47
+ *
48
+ * @throws RuntimePlaceholderResolutionError when a declared value
49
+ * references a runtime key that does not exist.
50
+ */
51
+ export function buildRunEnv(
52
+ declaredEnv: Readonly<Record<string, string>> | undefined,
53
+ runtimeEnv: Readonly<Record<string, unknown>>,
54
+ baseEnv: NodeJS.ProcessEnv = process.env,
55
+ ): Record<string, string> {
56
+ const env: Record<string, string> = {};
57
+
58
+ for (const key of RUN_ENV_BASE_KEYS) {
59
+ const value = baseEnv[key];
60
+ if (value !== undefined) env[key] = value;
61
+ }
62
+
63
+ if (!declaredEnv || Object.keys(declaredEnv).length === 0) {
64
+ // The only case whose behavior changed in oss#384 (previously the
65
+ // child inherited the full runner env) — leave a trace for operators.
66
+ console.log("run task declares no environment — child receives the minimal base env only");
67
+ return env;
68
+ }
69
+
70
+ for (const [key, value] of Object.entries(declaredEnv)) {
71
+ env[key] = resolveRuntimePlaceholdersStrict(
72
+ value,
73
+ runtimeEnv,
74
+ `environment "${key}"`,
75
+ );
76
+ }
77
+
78
+ return env;
79
+ }
@@ -3,8 +3,12 @@
3
3
  *
4
4
  * Converts plain event descriptors (safe for the Temporal deterministic
5
5
  * sandbox) into WorkflowExecutionEvent proto objects and sends them
6
- * alongside a status update via gRPC. Best-effort failures are logged
7
- * but do not fail the activity.
6
+ * alongside a status update via gRPC. Failures propagate so the local
7
+ * activity's retry policy fires safe because sequence numbers are
8
+ * workflow-assigned (stable across attempts) and the store skips
9
+ * already-persisted sequences, making retries idempotent. The workflow's
10
+ * emit wrappers catch after retries are exhausted; event emission never
11
+ * fails a run.
8
12
  *
9
13
  * Registered as proxyLocalActivities in engine-core.ts so the workflow
10
14
  * sandbox can emit events at task boundaries and approval gates.
@@ -140,6 +144,17 @@ function buildClient(): StigmerClient {
140
144
  });
141
145
  }
142
146
 
147
+ /**
148
+ * LEGACY sequence assignment — only for descriptors that arrive without a
149
+ * workflow-assigned `sequenceNumber`, i.e. replays of histories recorded
150
+ * before the "workflow-assigned-event-sequences" patch (see
151
+ * engine-core.ts). This counter is process-global: it is shared across
152
+ * every execution on the worker and resets on worker restart, which is
153
+ * the root cause of oss#308's silent event loss. Deliberately NOT fixed —
154
+ * pre-patch executions keep their old (flawed) behavior for the
155
+ * migration window. Delete together with the patch gate once pre-patch
156
+ * executions have drained.
157
+ */
143
158
  let sequenceCounter = 0;
144
159
 
145
160
  function nextSequence(): bigint {
@@ -148,33 +163,44 @@ function nextSequence(): bigint {
148
163
  }
149
164
 
150
165
  /**
151
- * Initialize the event sequence counter from the persisted high-water mark.
166
+ * Return the persisted event-log high-water mark for the execution, and
167
+ * seed the legacy process-global counter from it.
152
168
  *
153
- * On first run (no prior events), the counter stays at 0 and the first
154
- * event gets sequence_number = 1 identical to the original behavior.
169
+ * The workflow seeds its own sequence counter from the returned value
170
+ * (patched path); the legacy global seed remains for pre-patch replays,
171
+ * whose emit path still assigns sequences here in the activity.
155
172
  *
156
- * On recovery (events already persisted from a failed run), the counter
157
- * is set to the highest persisted sequence_number so that new events
158
- * continue from N+1, avoiding duplicate-key collisions in storage.
173
+ * On first run (no prior events) returns 0, so the first event gets
174
+ * sequence_number = 1. On recovery (events already persisted from a
175
+ * failed run) returns the highest persisted sequence_number, so new
176
+ * events continue from N+1.
159
177
  *
160
178
  * When executionId is empty (direct executeServerlessWorkflow without a
161
- * persisted execution), the counter resets to 0 as a safe fallback.
179
+ * persisted execution), returns 0 as a safe fallback.
180
+ *
181
+ * Returns a plain number — the value crosses back into the workflow
182
+ * through Temporal's JSON payload converter, which cannot carry BigInt.
162
183
  */
163
- export async function initSequenceFromEventLog(executionId: string): Promise<void> {
184
+ export async function initSequenceFromEventLog(executionId: string): Promise<number> {
164
185
  if (!executionId) {
165
186
  sequenceCounter = 0;
166
- return;
187
+ return 0;
167
188
  }
168
189
  const client = buildClient();
169
190
  const highWaterMark = await client.getEventLogHighWaterMark(executionId);
170
191
  sequenceCounter = Number(highWaterMark);
192
+ return sequenceCounter;
171
193
  }
172
194
 
173
195
  /** @internal Exported for unit testing only. */
174
196
  export function toProtoEvent(desc: WorkflowEventDescriptor): WorkflowExecutionEvent {
175
197
  const base = create(WorkflowExecutionEventSchema, {
176
198
  eventId: crypto.randomUUID(),
177
- sequenceNumber: nextSequence(),
199
+ // Workflow-assigned sequence when present (stable across activity
200
+ // retries); legacy activity-side assignment only for pre-patch replays.
201
+ sequenceNumber: desc.sequenceNumber !== undefined
202
+ ? BigInt(desc.sequenceNumber)
203
+ : nextSequence(),
178
204
  occurredAt: desc.occurredAt,
179
205
  taskName: desc.taskName ?? "",
180
206
  });
@@ -382,6 +408,14 @@ export function toProtoEvent(desc: WorkflowEventDescriptor): WorkflowExecutionEv
382
408
  return base;
383
409
  }
384
410
 
411
+ /**
412
+ * Emit workflow events (with the accompanying status snapshot) to the
413
+ * server. Errors propagate so the local activity retry policy fires;
414
+ * retries are idempotent because workflow-assigned sequence numbers are
415
+ * stable across attempts and the store skips already-persisted ones. The
416
+ * workflow-side emit wrappers absorb the failure after retries are
417
+ * exhausted, so a broken timeline write never fails the run.
418
+ */
385
419
  export async function emitWorkflowEvents(
386
420
  executionId: string,
387
421
  events: WorkflowEventDescriptor[],
@@ -389,64 +423,57 @@ export async function emitWorkflowEvents(
389
423
  ): Promise<void> {
390
424
  if (!executionId || events.length === 0) return;
391
425
 
392
- try {
393
- const client = buildClient();
394
- const protoEvents = events.map(toProtoEvent);
395
-
396
- const protoTasks = (taskStatuses ?? []).map(ts =>
397
- create(WorkflowTaskSchema, {
398
- taskId: ts.taskId ?? "",
399
- taskName: ts.taskName,
400
- taskType: TASK_KIND_TO_TYPE_MAP[ts.taskKind] ?? WorkflowTaskType.WORKFLOW_TASK_TYPE_UNSPECIFIED,
401
- status: TASK_STATUS_MAP[ts.status],
402
- startedAt: ts.startedAt ?? "",
403
- completedAt: ts.completedAt ?? "",
404
- error: ts.error ?? "",
405
- input: toJsonObject(ts.input),
406
- output: toJsonObject(ts.output),
407
- metadata: toJsonObject(ts.metadata),
408
- costMicros: BigInt(ts.costMicros ?? 0),
409
- inputTokens: BigInt(ts.inputTokens ?? 0),
410
- outputTokens: BigInt(ts.outputTokens ?? 0),
411
- uiHint: ts.uiHint ?? "",
412
- }),
413
- );
414
-
415
- const startedEvent = events.find(e => e.type === "execution_started");
416
- const completedEvent = events.find(e => e.type === "execution_completed");
417
- const failedEvent = events.find(e => e.type === "execution_failed");
418
-
419
- const statusFields: Record<string, unknown> = { tasks: protoTasks };
420
-
421
- if (startedEvent) {
422
- statusFields.phase = ExecutionPhase.EXECUTION_IN_PROGRESS;
423
- statusFields.startedAt = startedEvent.occurredAt;
424
- }
425
- if (completedEvent && completedEvent.type === "execution_completed") {
426
- statusFields.phase = ExecutionPhase.EXECUTION_COMPLETED;
427
- statusFields.completedAt = completedEvent.occurredAt;
428
- statusFields.totalCostMicros = BigInt(completedEvent.totalCostMicros);
429
- statusFields.totalInputTokens = BigInt(completedEvent.totalInputTokens ?? 0);
430
- statusFields.totalOutputTokens = BigInt(completedEvent.totalOutputTokens ?? 0);
431
- }
432
- if (failedEvent && failedEvent.type === "execution_failed") {
433
- statusFields.phase = ExecutionPhase.EXECUTION_FAILED;
434
- statusFields.completedAt = failedEvent.occurredAt;
435
- statusFields.error = failedEvent.error;
436
- }
437
-
438
- const input = create(WorkflowExecutionUpdateStatusInputSchema, {
439
- executionId,
440
- status: create(WorkflowExecutionStatusSchema, statusFields as Parameters<typeof create>[1]),
441
- events: protoEvents,
442
- });
443
- await client.workflowExecutionCommand.updateStatus(input);
444
- } catch (err) {
445
- console.error(
446
- `Failed to emit ${events.length} workflow event(s) for ${executionId}:`,
447
- err,
448
- );
426
+ const client = buildClient();
427
+ const protoEvents = events.map(toProtoEvent);
428
+
429
+ const protoTasks = (taskStatuses ?? []).map(ts =>
430
+ create(WorkflowTaskSchema, {
431
+ taskId: ts.taskId ?? "",
432
+ taskName: ts.taskName,
433
+ taskType: TASK_KIND_TO_TYPE_MAP[ts.taskKind] ?? WorkflowTaskType.WORKFLOW_TASK_TYPE_UNSPECIFIED,
434
+ status: TASK_STATUS_MAP[ts.status],
435
+ startedAt: ts.startedAt ?? "",
436
+ completedAt: ts.completedAt ?? "",
437
+ error: ts.error ?? "",
438
+ input: toJsonObject(ts.input),
439
+ output: toJsonObject(ts.output),
440
+ metadata: toJsonObject(ts.metadata),
441
+ costMicros: BigInt(ts.costMicros ?? 0),
442
+ inputTokens: BigInt(ts.inputTokens ?? 0),
443
+ outputTokens: BigInt(ts.outputTokens ?? 0),
444
+ uiHint: ts.uiHint ?? "",
445
+ }),
446
+ );
447
+
448
+ const startedEvent = events.find(e => e.type === "execution_started");
449
+ const completedEvent = events.find(e => e.type === "execution_completed");
450
+ const failedEvent = events.find(e => e.type === "execution_failed");
451
+
452
+ const statusFields: Record<string, unknown> = { tasks: protoTasks };
453
+
454
+ if (startedEvent) {
455
+ statusFields.phase = ExecutionPhase.EXECUTION_IN_PROGRESS;
456
+ statusFields.startedAt = startedEvent.occurredAt;
457
+ }
458
+ if (completedEvent && completedEvent.type === "execution_completed") {
459
+ statusFields.phase = ExecutionPhase.EXECUTION_COMPLETED;
460
+ statusFields.completedAt = completedEvent.occurredAt;
461
+ statusFields.totalCostMicros = BigInt(completedEvent.totalCostMicros);
462
+ statusFields.totalInputTokens = BigInt(completedEvent.totalInputTokens ?? 0);
463
+ statusFields.totalOutputTokens = BigInt(completedEvent.totalOutputTokens ?? 0);
464
+ }
465
+ if (failedEvent && failedEvent.type === "execution_failed") {
466
+ statusFields.phase = ExecutionPhase.EXECUTION_FAILED;
467
+ statusFields.completedAt = failedEvent.occurredAt;
468
+ statusFields.error = failedEvent.error;
449
469
  }
470
+
471
+ const input = create(WorkflowExecutionUpdateStatusInputSchema, {
472
+ executionId,
473
+ status: create(WorkflowExecutionStatusSchema, statusFields as Parameters<typeof create>[1]),
474
+ events: protoEvents,
475
+ });
476
+ await client.workflowExecutionCommand.updateStatus(input);
450
477
  }
451
478
 
452
479
  const PROTO_STATUS_TO_STRING: Record<number, string> = {
package/src/bootstrap.ts CHANGED
@@ -120,6 +120,11 @@ export async function resolveRunnerBootstrap(
120
120
  // (OSS / no signing key) and is handled by the runner, not treated as fatal.
121
121
  runnerAccessToken: discovered.runnerAccessToken,
122
122
  runnerAccessTokenExpiresInSeconds: discovered.runnerAccessTokenExpiresInSeconds,
123
+ // Server-managed payload-encryption keys ride the same best-effort lane:
124
+ // absent on OSS (env-configured keys) and on cloud servers predating key
125
+ // management. Note the explicit-address and localhost branches above return
126
+ // none by construction — key management only exists where discovery does.
127
+ payloadEncryption: discovered.payloadEncryption,
123
128
  };
124
129
  }
125
130
 
@@ -22,6 +22,14 @@ interface ClaimcheckMarker {
22
22
  key: string;
23
23
  size: number;
24
24
  compressed: boolean;
25
+ /**
26
+ * The relocated payload's original metadata, base64-encoded per value.
27
+ * Without it the restored payload would carry the marker's own
28
+ * "binary/claimcheck" encoding and no payload converter could interpret
29
+ * it. Absent on markers written before this field existed; those decode
30
+ * with the legacy (metadata-less) behavior.
31
+ */
32
+ metadata?: Record<string, string>;
25
33
  }
26
34
 
27
35
  export class ClaimcheckPayloadCodec implements PayloadCodec {
@@ -63,6 +71,7 @@ export class ClaimcheckPayloadCodec implements PayloadCodec {
63
71
  key,
64
72
  size: data.length,
65
73
  compressed,
74
+ metadata: serializeMetadata(payload.metadata),
66
75
  };
67
76
 
68
77
  return {
@@ -94,7 +103,9 @@ export class ClaimcheckPayloadCodec implements PayloadCodec {
94
103
  const dataBuf = marker.compressed ? decompress(rawBuf) : rawBuf;
95
104
 
96
105
  return {
97
- metadata: payload.metadata,
106
+ metadata: marker.metadata
107
+ ? deserializeMetadata(marker.metadata)
108
+ : payload.metadata,
98
109
  data: dataBuf,
99
110
  };
100
111
  }
@@ -105,3 +116,24 @@ export class ClaimcheckPayloadCodec implements PayloadCodec {
105
116
  return Buffer.from(encoding).toString("utf-8") === MARKER_ENCODING_VALUE;
106
117
  }
107
118
  }
119
+
120
+ function serializeMetadata(
121
+ metadata: Payload["metadata"],
122
+ ): Record<string, string> | undefined {
123
+ if (!metadata) return undefined;
124
+ const out: Record<string, string> = {};
125
+ for (const [key, value] of Object.entries(metadata)) {
126
+ if (value) out[key] = Buffer.from(value).toString("base64");
127
+ }
128
+ return out;
129
+ }
130
+
131
+ function deserializeMetadata(
132
+ metadata: Record<string, string>,
133
+ ): Record<string, Uint8Array> {
134
+ const out: Record<string, Uint8Array> = {};
135
+ for (const [key, value] of Object.entries(metadata)) {
136
+ out[key] = Buffer.from(value, "base64");
137
+ }
138
+ return out;
139
+ }