@stigmer/runner 3.14.0 → 3.15.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 (331) hide show
  1. package/dist/.build-fingerprint +1 -1
  2. package/dist/__test-utils__/execution-record-fixture.d.ts +47 -0
  3. package/dist/__test-utils__/execution-record-fixture.js +68 -0
  4. package/dist/__test-utils__/execution-record-fixture.js.map +1 -0
  5. package/dist/__test-utils__/harness-contract/types.d.ts +166 -0
  6. package/dist/__test-utils__/harness-contract/types.js +49 -0
  7. package/dist/__test-utils__/harness-contract/types.js.map +1 -0
  8. package/dist/__test-utils__/hermetic-activity.d.ts +268 -0
  9. package/dist/__test-utils__/hermetic-activity.js +385 -0
  10. package/dist/__test-utils__/hermetic-activity.js.map +1 -0
  11. package/dist/__test-utils__/mock-client.d.ts +13 -0
  12. package/dist/__test-utils__/mock-client.js +45 -0
  13. package/dist/__test-utils__/mock-client.js.map +1 -0
  14. package/dist/__test-utils__/mock-workspace.d.ts +15 -0
  15. package/dist/__test-utils__/mock-workspace.js +21 -0
  16. package/dist/__test-utils__/mock-workspace.js.map +1 -0
  17. package/dist/__test-utils__/model-registry-fixture.d.ts +56 -0
  18. package/dist/__test-utils__/model-registry-fixture.js +66 -0
  19. package/dist/__test-utils__/model-registry-fixture.js.map +1 -0
  20. package/dist/__test-utils__/turn-input-fixture.d.ts +60 -0
  21. package/dist/__test-utils__/turn-input-fixture.js +118 -0
  22. package/dist/__test-utils__/turn-input-fixture.js.map +1 -0
  23. package/dist/activities/execute-cursor/__test-utils__/contract-subject.d.ts +107 -0
  24. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js +344 -0
  25. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js.map +1 -0
  26. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.d.ts +20 -0
  27. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js +58 -0
  28. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js.map +1 -1
  29. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js +2 -32
  30. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js.map +1 -1
  31. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +148 -0
  32. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +257 -0
  33. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -0
  34. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.d.ts +183 -0
  35. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js +262 -0
  36. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js.map +1 -0
  37. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.d.ts +138 -0
  38. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js +191 -0
  39. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js.map +1 -0
  40. package/dist/activities/execute-cursor/adapter.d.ts +55 -0
  41. package/dist/activities/execute-cursor/adapter.js +119 -0
  42. package/dist/activities/execute-cursor/adapter.js.map +1 -0
  43. package/dist/activities/execute-cursor/approval-state.d.ts +2 -2
  44. package/dist/activities/execute-cursor/approval-state.js.map +1 -1
  45. package/dist/activities/execute-cursor/capture-flow.d.ts +15 -30
  46. package/dist/activities/execute-cursor/capture-flow.js +17 -26
  47. package/dist/activities/execute-cursor/capture-flow.js.map +1 -1
  48. package/dist/activities/execute-cursor/cursor-capabilities.d.ts +23 -0
  49. package/dist/activities/execute-cursor/cursor-capabilities.js +33 -0
  50. package/dist/activities/execute-cursor/cursor-capabilities.js.map +1 -0
  51. package/dist/activities/execute-cursor/cursor-mcp-config.d.ts +2 -2
  52. package/dist/activities/execute-cursor/cursor-mcp-config.js.map +1 -1
  53. package/dist/activities/execute-cursor/fetch-interceptor.d.ts +15 -25
  54. package/dist/activities/execute-cursor/fetch-interceptor.js +39 -33
  55. package/dist/activities/execute-cursor/fetch-interceptor.js.map +1 -1
  56. package/dist/activities/execute-cursor/http2-interceptor.d.ts +21 -17
  57. package/dist/activities/execute-cursor/http2-interceptor.js +38 -31
  58. package/dist/activities/execute-cursor/http2-interceptor.js.map +1 -1
  59. package/dist/activities/execute-cursor/message-translator.d.ts +28 -19
  60. package/dist/activities/execute-cursor/message-translator.js +76 -27
  61. package/dist/activities/execute-cursor/message-translator.js.map +1 -1
  62. package/dist/activities/execute-cursor/prompt-builder.d.ts +180 -11
  63. package/dist/activities/execute-cursor/prompt-builder.js +171 -0
  64. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  65. package/dist/activities/execute-cursor/rejection-capture.d.ts +3 -6
  66. package/dist/activities/execute-cursor/rejection-capture.js +5 -7
  67. package/dist/activities/execute-cursor/rejection-capture.js.map +1 -1
  68. package/dist/activities/execute-cursor/session-lifecycle.d.ts +1 -4
  69. package/dist/activities/execute-cursor/session-lifecycle.js.map +1 -1
  70. package/dist/activities/execute-cursor/turn-boundary.d.ts +1 -1
  71. package/dist/activities/execute-cursor/turn-settle.d.ts +49 -0
  72. package/dist/activities/execute-cursor/turn-settle.js +507 -0
  73. package/dist/activities/execute-cursor/turn-settle.js.map +1 -0
  74. package/dist/activities/execute-cursor/turn-setup.d.ts +173 -0
  75. package/dist/activities/execute-cursor/turn-setup.js +496 -0
  76. package/dist/activities/execute-cursor/turn-setup.js.map +1 -0
  77. package/dist/activities/execute-cursor/turn-stream.d.ts +41 -71
  78. package/dist/activities/execute-cursor/turn-stream.js +70 -135
  79. package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
  80. package/dist/activities/execute-cursor/turn.d.ts +43 -0
  81. package/dist/activities/execute-cursor/turn.js +222 -0
  82. package/dist/activities/execute-cursor/turn.js.map +1 -0
  83. package/dist/activities/execute-cursor/usage-pricing.d.ts +38 -0
  84. package/dist/activities/execute-cursor/usage-pricing.js +50 -0
  85. package/dist/activities/execute-cursor/usage-pricing.js.map +1 -0
  86. package/dist/activities/execute-deep-agent/approval-file-change.d.ts +1 -1
  87. package/dist/activities/execute-deep-agent/approval-file-change.js +1 -1
  88. package/dist/activities/execute-deep-agent/environment.js +1 -1
  89. package/dist/activities/execute-deep-agent/environment.js.map +1 -1
  90. package/dist/activities/execute-deep-agent/setup.js +3 -2
  91. package/dist/activities/execute-deep-agent/setup.js.map +1 -1
  92. package/dist/activities/hydrate-workflow-execution.js +1 -1
  93. package/dist/activities/hydrate-workflow-execution.js.map +1 -1
  94. package/dist/config.d.ts +15 -0
  95. package/dist/config.js.map +1 -1
  96. package/dist/harness/capabilities.d.ts +87 -0
  97. package/dist/harness/capabilities.js +37 -0
  98. package/dist/harness/capabilities.js.map +1 -0
  99. package/dist/harness/persist-chokepoint.d.ts +74 -0
  100. package/dist/harness/persist-chokepoint.js +88 -0
  101. package/dist/harness/persist-chokepoint.js.map +1 -0
  102. package/dist/harness/registry.d.ts +106 -0
  103. package/dist/harness/registry.js +168 -0
  104. package/dist/harness/registry.js.map +1 -0
  105. package/dist/harness/run-turn.d.ts +53 -0
  106. package/dist/harness/run-turn.js +528 -0
  107. package/dist/harness/run-turn.js.map +1 -0
  108. package/dist/harness/stop-controller.d.ts +50 -0
  109. package/dist/harness/stop-controller.js +62 -0
  110. package/dist/harness/stop-controller.js.map +1 -0
  111. package/dist/harness/terminal-table.d.ts +141 -0
  112. package/dist/harness/terminal-table.js +239 -0
  113. package/dist/harness/terminal-table.js.map +1 -0
  114. package/dist/harness/turn-context.d.ts +523 -0
  115. package/dist/harness/turn-context.js +739 -0
  116. package/dist/harness/turn-context.js.map +1 -0
  117. package/dist/harness/types.d.ts +448 -0
  118. package/dist/harness/types.js +64 -0
  119. package/dist/harness/types.js.map +1 -0
  120. package/dist/harness/usage-accumulator.d.ts +68 -0
  121. package/dist/harness/usage-accumulator.js +101 -0
  122. package/dist/harness/usage-accumulator.js.map +1 -0
  123. package/dist/harness-adapters.d.ts +27 -0
  124. package/dist/harness-adapters.js +28 -0
  125. package/dist/harness-adapters.js.map +1 -0
  126. package/dist/main.js.map +1 -1
  127. package/dist/runner-manager.js +64 -48
  128. package/dist/runner-manager.js.map +1 -1
  129. package/dist/runner.d.ts +5 -4
  130. package/dist/runner.js +65 -64
  131. package/dist/runner.js.map +1 -1
  132. package/dist/shared/approval-policy.d.ts +1 -1
  133. package/dist/shared/approval-policy.js.map +1 -1
  134. package/dist/{activities/execute-cursor → shared}/attachment-resolver.d.ts +2 -2
  135. package/dist/{activities/execute-cursor → shared}/attachment-resolver.js +5 -5
  136. package/dist/shared/attachment-resolver.js.map +1 -0
  137. package/dist/{activities/execute-cursor → shared}/blueprint-resolver.d.ts +7 -5
  138. package/dist/{activities/execute-cursor → shared}/blueprint-resolver.js +3 -63
  139. package/dist/shared/blueprint-resolver.js.map +1 -0
  140. package/dist/shared/channel-attachment.d.ts +1 -1
  141. package/dist/shared/channel-attachment.js.map +1 -1
  142. package/dist/{activities/execute-cursor → shared}/cost-guard.d.ts +5 -1
  143. package/dist/{activities/execute-cursor → shared}/cost-guard.js +5 -1
  144. package/dist/shared/cost-guard.js.map +1 -0
  145. package/dist/{activities/execute-cursor → shared}/env-resolver.d.ts +1 -1
  146. package/dist/shared/env-resolver.js.map +1 -0
  147. package/dist/{activities/execute-cursor → shared}/exact-apply.d.ts +1 -1
  148. package/dist/{activities/execute-cursor → shared}/exact-apply.js +6 -6
  149. package/dist/shared/exact-apply.js.map +1 -0
  150. package/dist/shared/execution-context.d.ts +35 -0
  151. package/dist/shared/execution-context.js +38 -0
  152. package/dist/shared/execution-context.js.map +1 -0
  153. package/dist/{activities/execute-cursor → shared}/extract-structured-output.d.ts +5 -2
  154. package/dist/{activities/execute-cursor → shared}/extract-structured-output.js +9 -6
  155. package/dist/shared/extract-structured-output.js.map +1 -0
  156. package/dist/shared/filereview/capture.d.ts +1 -1
  157. package/dist/shared/filereview/capture.js +1 -1
  158. package/dist/shared/heartbeat.d.ts +13 -11
  159. package/dist/shared/heartbeat.js +14 -29
  160. package/dist/shared/heartbeat.js.map +1 -1
  161. package/dist/{activities/execute-cursor → shared}/persist-decision.d.ts +5 -2
  162. package/dist/{activities/execute-cursor → shared}/persist-decision.js +4 -1
  163. package/dist/shared/persist-decision.js.map +1 -0
  164. package/dist/{activities/execute-cursor → shared}/skill-resolver.d.ts +16 -3
  165. package/dist/{activities/execute-cursor → shared}/skill-resolver.js +12 -4
  166. package/dist/shared/skill-resolver.js.map +1 -0
  167. package/dist/shared/subagent-rows.d.ts +21 -0
  168. package/dist/shared/subagent-rows.js +34 -0
  169. package/dist/shared/subagent-rows.js.map +1 -0
  170. package/dist/shared/worker-shutdown.d.ts +43 -16
  171. package/dist/shared/worker-shutdown.js +28 -13
  172. package/dist/shared/worker-shutdown.js.map +1 -1
  173. package/dist/shared/workspace/platform-dir.d.ts +1 -1
  174. package/dist/shared/workspace/platform-dir.js +1 -1
  175. package/dist/shared/workspace/session-provision.d.ts +54 -0
  176. package/dist/{activities/execute-cursor/workspace-provision.js → shared/workspace/session-provision.js} +15 -12
  177. package/dist/shared/workspace/session-provision.js.map +1 -0
  178. package/package.json +4 -4
  179. package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +325 -0
  180. package/src/__test-utils__/config-fixture.ts +63 -0
  181. package/src/__test-utils__/execution-record-fixture.ts +104 -0
  182. package/src/__test-utils__/harness-boot-order-child.ts +58 -0
  183. package/src/__test-utils__/harness-contract/contract.ts +581 -0
  184. package/src/__test-utils__/harness-contract/recording-sink.ts +107 -0
  185. package/src/__test-utils__/harness-contract/runtime-contract.ts +666 -0
  186. package/src/__test-utils__/harness-contract/scripted-adapter.ts +349 -0
  187. package/src/__test-utils__/harness-contract/types.ts +176 -0
  188. package/src/__test-utils__/hermetic-activity.ts +502 -0
  189. package/src/__test-utils__/model-registry-fixture.ts +72 -0
  190. package/src/__test-utils__/module-specifiers.ts +82 -0
  191. package/src/__test-utils__/proto-helpers.ts +25 -0
  192. package/src/__test-utils__/turn-input-fixture.ts +155 -0
  193. package/src/__tests__/harness-boot-order.test.ts +77 -0
  194. package/src/__tests__/harness-contract.test.ts +27 -0
  195. package/src/__tests__/runner-manager.test.ts +18 -0
  196. package/src/activities/execute-cursor/__test-utils__/__tests__/scripted-double.test.ts +102 -0
  197. package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +396 -0
  198. package/src/activities/execute-cursor/__test-utils__/cursor-hook-harness.ts +66 -0
  199. package/src/activities/execute-cursor/__test-utils__/gateway-substrate.ts +2 -43
  200. package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +342 -0
  201. package/src/activities/execute-cursor/__test-utils__/scripted-agent.ts +368 -0
  202. package/src/activities/execute-cursor/__test-utils__/scripted-sdk.ts +254 -0
  203. package/src/activities/execute-cursor/__tests__/adapter-is-temporal-free.test.ts +45 -0
  204. package/src/activities/execute-cursor/__tests__/approval-decisions-agree.test.ts +90 -0
  205. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +7 -8
  206. package/src/activities/execute-cursor/__tests__/capture-flow.test.ts +28 -1
  207. package/src/activities/execute-cursor/__tests__/deny-gate-exact-apply.test.ts +1 -1
  208. package/src/activities/execute-cursor/__tests__/fetch-interceptor.test.ts +64 -6
  209. package/src/activities/execute-cursor/__tests__/hermetic/deny-and-retry.test.ts +228 -0
  210. package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +180 -0
  211. package/src/activities/execute-cursor/__tests__/hermetic/goldens/cost-cap.status.json +53 -0
  212. package/src/activities/execute-cursor/__tests__/hermetic/goldens/deny-and-retry.turn1.status.json +55 -0
  213. package/src/activities/execute-cursor/__tests__/hermetic/goldens/deny-and-retry.turn2.status.json +77 -0
  214. package/src/activities/execute-cursor/__tests__/hermetic/goldens/file-review-capture.status.json +126 -0
  215. package/src/activities/execute-cursor/__tests__/hermetic/goldens/pause.status.json +40 -0
  216. package/src/activities/execute-cursor/__tests__/hermetic/goldens/plain-turn.status.json +48 -0
  217. package/src/activities/execute-cursor/__tests__/hermetic/goldens/platform-stop.status.json +56 -0
  218. package/src/activities/execute-cursor/__tests__/hermetic/goldens/recovery-fresh-agent.status.json +53 -0
  219. package/src/activities/execute-cursor/__tests__/hermetic/goldens/recovery-transport-timeout.status.json +48 -0
  220. package/src/activities/execute-cursor/__tests__/hermetic/goldens/resolution-error.status.json +18 -0
  221. package/src/activities/execute-cursor/__tests__/hermetic/goldens/run-cancelled.status.json +36 -0
  222. package/src/activities/execute-cursor/__tests__/hermetic/goldens/run-error-non-retryable.status.json +37 -0
  223. package/src/activities/execute-cursor/__tests__/hermetic/goldens/sdk-error-at-create.status.json +38 -0
  224. package/src/activities/execute-cursor/__tests__/hermetic/goldens/stall.status.json +59 -0
  225. package/src/activities/execute-cursor/__tests__/hermetic/goldens/tool-call.status.json +68 -0
  226. package/src/activities/execute-cursor/__tests__/hermetic/goldens/unattributed-hook-block.status.json +79 -0
  227. package/src/activities/execute-cursor/__tests__/hermetic/goldens/worker-shutdown.status.json +42 -0
  228. package/src/activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts +170 -0
  229. package/src/activities/execute-cursor/__tests__/hermetic/pause-vs-shutdown.test.ts +205 -0
  230. package/src/activities/execute-cursor/__tests__/hermetic/plain-turn.test.ts +171 -0
  231. package/src/activities/execute-cursor/__tests__/hermetic/recovery-fresh-agent.test.ts +156 -0
  232. package/src/activities/execute-cursor/__tests__/hermetic/run-wait-arms.test.ts +286 -0
  233. package/src/activities/execute-cursor/__tests__/hermetic/stream-self-stop-arms.test.ts +332 -0
  234. package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +193 -0
  235. package/src/activities/execute-cursor/__tests__/hermetic/tool-call.test.ts +137 -0
  236. package/src/activities/execute-cursor/__tests__/hermetic/unattributed-hook-block.test.ts +185 -0
  237. package/src/activities/execute-cursor/__tests__/hermetic/workspace-lock-timeout.test.ts +151 -0
  238. package/src/activities/execute-cursor/__tests__/http2-interceptor.test.ts +65 -35
  239. package/src/activities/execute-cursor/__tests__/message-translator.test.ts +0 -40
  240. package/src/activities/execute-cursor/__tests__/same-identity-reproposal.test.ts +171 -0
  241. package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +118 -243
  242. package/src/activities/execute-cursor/__tests__/usage-pricing.test.ts +84 -0
  243. package/src/activities/execute-cursor/adapter.ts +138 -0
  244. package/src/activities/execute-cursor/approval-state.ts +2 -2
  245. package/src/activities/execute-cursor/capture-flow.ts +18 -41
  246. package/src/activities/execute-cursor/cursor-capabilities.ts +35 -0
  247. package/src/activities/execute-cursor/cursor-mcp-config.ts +2 -2
  248. package/src/activities/execute-cursor/fetch-interceptor.ts +48 -45
  249. package/src/activities/execute-cursor/http2-interceptor.ts +47 -34
  250. package/src/activities/execute-cursor/message-translator.ts +90 -45
  251. package/src/activities/execute-cursor/prompt-builder.ts +327 -12
  252. package/src/activities/execute-cursor/rejection-capture.ts +5 -12
  253. package/src/activities/execute-cursor/session-lifecycle.ts +1 -5
  254. package/src/activities/execute-cursor/turn-boundary.ts +1 -1
  255. package/src/activities/execute-cursor/turn-settle.ts +601 -0
  256. package/src/activities/execute-cursor/turn-setup.ts +645 -0
  257. package/src/activities/execute-cursor/turn-stream.ts +84 -210
  258. package/src/activities/execute-cursor/turn.ts +240 -0
  259. package/src/activities/execute-cursor/usage-pricing.ts +67 -0
  260. package/src/activities/execute-deep-agent/approval-file-change.ts +1 -1
  261. package/src/activities/execute-deep-agent/environment.ts +1 -1
  262. package/src/activities/execute-deep-agent/setup.ts +3 -2
  263. package/src/activities/hydrate-workflow-execution.ts +1 -1
  264. package/src/config.ts +13 -0
  265. package/src/harness/__tests__/import-direction.test.ts +168 -0
  266. package/src/harness/__tests__/persist-chokepoint.test.ts +146 -0
  267. package/src/harness/__tests__/registry.test.ts +168 -0
  268. package/src/harness/__tests__/run-turn.test.ts +165 -0
  269. package/src/harness/__tests__/stop-controller.test.ts +49 -0
  270. package/src/harness/__tests__/turn-context.test.ts +178 -0
  271. package/src/harness/__tests__/usage-accumulator.test.ts +83 -0
  272. package/src/harness/capabilities.ts +92 -0
  273. package/src/harness/persist-chokepoint.ts +112 -0
  274. package/src/harness/registry.ts +197 -0
  275. package/src/harness/run-turn.ts +618 -0
  276. package/src/harness/stop-controller.ts +83 -0
  277. package/src/harness/terminal-table.ts +276 -0
  278. package/src/harness/turn-context.ts +1028 -0
  279. package/src/harness/types.ts +473 -0
  280. package/src/harness/usage-accumulator.ts +122 -0
  281. package/src/harness-adapters.ts +30 -0
  282. package/src/main.ts +1 -1
  283. package/src/runner-manager.ts +68 -61
  284. package/src/runner.ts +67 -78
  285. package/src/shared/__tests__/attachment-naming.test.ts +1 -1
  286. package/src/{activities/execute-cursor → shared}/__tests__/attachment-resolver.test.ts +6 -4
  287. package/src/{activities/execute-cursor → shared}/__tests__/cost-guard.test.ts +2 -1
  288. package/src/{activities/execute-cursor → shared}/__tests__/exact-apply.test.ts +3 -3
  289. package/src/{activities/execute-cursor → shared}/__tests__/extract-structured-output.test.ts +8 -8
  290. package/src/{activities/execute-cursor → shared}/__tests__/persist-decision.test.ts +4 -2
  291. package/src/{activities/execute-cursor → shared}/__tests__/skill-resolver.test.ts +1 -1
  292. package/src/shared/__tests__/subagent-rows.test.ts +34 -0
  293. package/src/shared/__tests__/worker-shutdown.test.ts +44 -39
  294. package/src/shared/approval-policy.ts +1 -1
  295. package/src/{activities/execute-cursor → shared}/attachment-resolver.ts +6 -6
  296. package/src/{activities/execute-cursor → shared}/blueprint-resolver.ts +7 -78
  297. package/src/shared/channel-attachment.ts +1 -1
  298. package/src/{activities/execute-cursor → shared}/cost-guard.ts +5 -1
  299. package/src/{activities/execute-cursor → shared}/env-resolver.ts +1 -1
  300. package/src/{activities/execute-cursor → shared}/exact-apply.ts +7 -7
  301. package/src/shared/execution-context.ts +45 -0
  302. package/src/{activities/execute-cursor → shared}/extract-structured-output.ts +10 -7
  303. package/src/shared/filereview/capture.ts +1 -1
  304. package/src/shared/heartbeat.ts +13 -33
  305. package/src/{activities/execute-cursor → shared}/persist-decision.ts +5 -2
  306. package/src/{activities/execute-cursor → shared}/skill-resolver.ts +20 -6
  307. package/src/shared/subagent-rows.ts +39 -0
  308. package/src/shared/worker-shutdown.ts +55 -25
  309. package/src/{activities/execute-cursor/__tests__/workspace-provision.test.ts → shared/workspace/__tests__/session-provision.test.ts} +25 -28
  310. package/src/shared/workspace/platform-dir.ts +1 -1
  311. package/src/{activities/execute-cursor/workspace-provision.ts → shared/workspace/session-provision.ts} +29 -16
  312. package/dist/activities/execute-cursor/attachment-resolver.js.map +0 -1
  313. package/dist/activities/execute-cursor/blueprint-resolver.js.map +0 -1
  314. package/dist/activities/execute-cursor/cost-guard.js.map +0 -1
  315. package/dist/activities/execute-cursor/env-resolver.js.map +0 -1
  316. package/dist/activities/execute-cursor/exact-apply.js.map +0 -1
  317. package/dist/activities/execute-cursor/extract-structured-output.js.map +0 -1
  318. package/dist/activities/execute-cursor/index.d.ts +0 -209
  319. package/dist/activities/execute-cursor/index.js +0 -2345
  320. package/dist/activities/execute-cursor/index.js.map +0 -1
  321. package/dist/activities/execute-cursor/persist-decision.js.map +0 -1
  322. package/dist/activities/execute-cursor/skill-resolver.js.map +0 -1
  323. package/dist/activities/execute-cursor/usage-accumulator.d.ts +0 -89
  324. package/dist/activities/execute-cursor/usage-accumulator.js +0 -121
  325. package/dist/activities/execute-cursor/usage-accumulator.js.map +0 -1
  326. package/dist/activities/execute-cursor/workspace-provision.d.ts +0 -42
  327. package/dist/activities/execute-cursor/workspace-provision.js.map +0 -1
  328. package/src/activities/execute-cursor/__tests__/usage-accumulator.test.ts +0 -164
  329. package/src/activities/execute-cursor/index.ts +0 -2876
  330. package/src/activities/execute-cursor/usage-accumulator.ts +0 -169
  331. /package/dist/{activities/execute-cursor → shared}/env-resolver.js +0 -0
@@ -1 +1 @@
1
- {"hash":"7c856383e6ad237f","builtAt":"2026-09-10T09:47:17.422Z","fileCount":293}
1
+ {"hash":"2ac96be487c6ce2c","builtAt":"2026-09-13T09:42:32.154Z","fileCount":325}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * The four resources of one execution, wired by id into the chain the turn
3
+ * runtime resolves (`execution.spec.sessionId` → `session.spec.
4
+ * agentInstanceId` → `agentInstance.spec.agentId` → the agent), as an
5
+ * `ExecutionRecord` the hermetic client answers from.
6
+ *
7
+ * Harness-agnostic: the record is the control plane's, and the runtime's
8
+ * phases read it the same way whatever engine runs the turn. A harness's
9
+ * driver supplies its own fixture ids and model (`execute-cursor/__test-
10
+ * utils__/hermetic-cursor.ts` `cursorExecutionRecord`); the runtime's own
11
+ * tests use the defaults. Ids are fixed so goldens are readable and
12
+ * byte-stable.
13
+ */
14
+ import type { WorkspaceEntry } from "@stigmer/protos/ai/stigmer/agentic/session/v1/workspace_pb";
15
+ import { ExecutionRecord, type ExecutionRecordInput } from "./hermetic-activity.js";
16
+ /** The ids a record's four resources carry. */
17
+ export interface ExecutionRecordIds {
18
+ readonly org: string;
19
+ readonly executionId: string;
20
+ readonly sessionId: string;
21
+ readonly agentInstanceId: string;
22
+ readonly agentId: string;
23
+ readonly agentName: string;
24
+ }
25
+ export declare const DEFAULT_RECORD_IDS: ExecutionRecordIds;
26
+ export interface ExecutionRecordOptions {
27
+ /** The user's message for this execution. */
28
+ readonly message: string;
29
+ /** The agent's instructions (system prompt body). */
30
+ readonly instructions?: string;
31
+ /** Session workspace entries (a `local_path` entry turns on capture mode). */
32
+ readonly workspaceEntries?: WorkspaceEntry[];
33
+ /** The requested model; the pinned fixture model when omitted. */
34
+ readonly modelName?: string;
35
+ readonly autoApproveAll?: boolean;
36
+ /**
37
+ * `ExecutionConfig.max_cost_usd`: the per-message cost budget the runtime
38
+ * enforces as a hard stop (cost-guard.ts). Omitted or 0 = no cap, the
39
+ * proto's default. Priced against the registry fixture's round numbers, so
40
+ * a scenario can state its overrun exactly (600 000 input tokens = $0.60).
41
+ */
42
+ readonly maxCostUsd?: number;
43
+ /** The control plane's STOP lever; see `ExecutionRecordInput.controlSignal`. */
44
+ readonly controlSignal?: ExecutionRecordInput["controlSignal"];
45
+ readonly ids?: ExecutionRecordIds;
46
+ }
47
+ export declare function executionRecordFixture(options: ExecutionRecordOptions): ExecutionRecord;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * The four resources of one execution, wired by id into the chain the turn
3
+ * runtime resolves (`execution.spec.sessionId` → `session.spec.
4
+ * agentInstanceId` → `agentInstance.spec.agentId` → the agent), as an
5
+ * `ExecutionRecord` the hermetic client answers from.
6
+ *
7
+ * Harness-agnostic: the record is the control plane's, and the runtime's
8
+ * phases read it the same way whatever engine runs the turn. A harness's
9
+ * driver supplies its own fixture ids and model (`execute-cursor/__test-
10
+ * utils__/hermetic-cursor.ts` `cursorExecutionRecord`); the runtime's own
11
+ * tests use the defaults. Ids are fixed so goldens are readable and
12
+ * byte-stable.
13
+ */
14
+ import { create } from "@bufbuild/protobuf";
15
+ import { AgentExecutionSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
16
+ import { AgentExecutionSpecSchema, ExecutionConfigSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/spec_pb";
17
+ import { SessionSchema } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
18
+ import { SessionSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/session/v1/spec_pb";
19
+ import { AgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
20
+ import { AgentSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
21
+ import { AgentInstanceSchema } from "@stigmer/protos/ai/stigmer/agentic/agentinstance/v1/api_pb";
22
+ import { AgentInstanceSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/agentinstance/v1/spec_pb";
23
+ import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
24
+ import { ExecutionRecord } from "./hermetic-activity.js";
25
+ import { FIXTURE_MODEL } from "./model-registry-fixture.js";
26
+ export const DEFAULT_RECORD_IDS = {
27
+ org: "hermetic-org",
28
+ executionId: "aex_hermetic_0001",
29
+ sessionId: "ses_hermetic_0001",
30
+ agentInstanceId: "ain_hermetic_0001",
31
+ agentId: "agt_hermetic_0001",
32
+ agentName: "hermetic-agent",
33
+ };
34
+ export function executionRecordFixture(options) {
35
+ const ids = options.ids ?? DEFAULT_RECORD_IDS;
36
+ const execution = create(AgentExecutionSchema, {
37
+ metadata: create(ApiResourceMetadataSchema, { id: ids.executionId, org: ids.org, name: ids.executionId }),
38
+ spec: create(AgentExecutionSpecSchema, {
39
+ sessionId: ids.sessionId,
40
+ message: options.message,
41
+ autoApproveAll: options.autoApproveAll ?? false,
42
+ executionConfig: create(ExecutionConfigSchema, {
43
+ modelName: options.modelName ?? FIXTURE_MODEL,
44
+ maxCostUsd: options.maxCostUsd ?? 0,
45
+ }),
46
+ }),
47
+ });
48
+ const session = create(SessionSchema, {
49
+ metadata: create(ApiResourceMetadataSchema, { id: ids.sessionId, org: ids.org, name: ids.sessionId }),
50
+ spec: create(SessionSpecSchema, {
51
+ agentInstanceId: ids.agentInstanceId,
52
+ workspaceEntries: options.workspaceEntries ?? [],
53
+ }),
54
+ });
55
+ const agentInstance = create(AgentInstanceSchema, {
56
+ metadata: create(ApiResourceMetadataSchema, { id: ids.agentInstanceId, org: ids.org, name: ids.agentInstanceId }),
57
+ spec: create(AgentInstanceSpecSchema, { agentId: ids.agentId }),
58
+ });
59
+ const agent = create(AgentSchema, {
60
+ metadata: create(ApiResourceMetadataSchema, { id: ids.agentId, org: ids.org, name: ids.agentName }),
61
+ spec: create(AgentSpecSchema, {
62
+ description: "Hermetic fixture agent",
63
+ instructions: options.instructions ?? "You are the hermetic fixture agent. Answer briefly.",
64
+ }),
65
+ });
66
+ return new ExecutionRecord({ execution, session, agentInstance, agent, controlSignal: options.controlSignal });
67
+ }
68
+ //# sourceMappingURL=execution-record-fixture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution-record-fixture.js","sourceRoot":"","sources":["../../src/__test-utils__/execution-record-fixture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAuB,MAAM,6DAA6D,CAAC;AACxH,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,8DAA8D,CAAC;AAC/H,OAAO,EAAE,aAAa,EAAgB,MAAM,sDAAsD,CAAC;AACnG,OAAO,EAAE,iBAAiB,EAAE,MAAM,uDAAuD,CAAC;AAE1F,OAAO,EAAE,WAAW,EAAc,MAAM,oDAAoD,CAAC;AAC7F,OAAO,EAAE,eAAe,EAAE,MAAM,qDAAqD,CAAC;AACtF,OAAO,EAAE,mBAAmB,EAAsB,MAAM,4DAA4D,CAAC;AACrH,OAAO,EAAE,uBAAuB,EAAE,MAAM,6DAA6D,CAAC;AACtG,OAAO,EAAE,yBAAyB,EAAE,MAAM,4DAA4D,CAAC;AAEvG,OAAO,EAAE,eAAe,EAA6B,MAAM,wBAAwB,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAY5D,MAAM,CAAC,MAAM,kBAAkB,GAAuB;IACpD,GAAG,EAAE,cAAc;IACnB,WAAW,EAAE,mBAAmB;IAChC,SAAS,EAAE,mBAAmB;IAC9B,eAAe,EAAE,mBAAmB;IACpC,OAAO,EAAE,mBAAmB;IAC5B,SAAS,EAAE,gBAAgB;CAC5B,CAAC;AAwBF,MAAM,UAAU,sBAAsB,CAAC,OAA+B;IACpE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,kBAAkB,CAAC;IAC9C,MAAM,SAAS,GAAmB,MAAM,CAAC,oBAAoB,EAAE;QAC7D,QAAQ,EAAE,MAAM,CAAC,yBAAyB,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,WAAW,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC;QACzG,IAAI,EAAE,MAAM,CAAC,wBAAwB,EAAE;YACrC,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,KAAK;YAC/C,eAAe,EAAE,MAAM,CAAC,qBAAqB,EAAE;gBAC7C,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,aAAa;gBAC7C,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,CAAC;aACpC,CAAC;SACH,CAAC;KACH,CAAC,CAAC;IACH,MAAM,OAAO,GAAY,MAAM,CAAC,aAAa,EAAE;QAC7C,QAAQ,EAAE,MAAM,CAAC,yBAAyB,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;QACrG,IAAI,EAAE,MAAM,CAAC,iBAAiB,EAAE;YAC9B,eAAe,EAAE,GAAG,CAAC,eAAe;YACpC,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,IAAI,EAAE;SACjD,CAAC;KACH,CAAC,CAAC;IACH,MAAM,aAAa,GAAkB,MAAM,CAAC,mBAAmB,EAAE;QAC/D,QAAQ,EAAE,MAAM,CAAC,yBAAyB,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,eAAe,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,eAAe,EAAE,CAAC;QACjH,IAAI,EAAE,MAAM,CAAC,uBAAuB,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;KAChE,CAAC,CAAC;IACH,MAAM,KAAK,GAAU,MAAM,CAAC,WAAW,EAAE;QACvC,QAAQ,EAAE,MAAM,CAAC,yBAAyB,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;QACnG,IAAI,EAAE,MAAM,CAAC,eAAe,EAAE;YAC5B,WAAW,EAAE,wBAAwB;YACrC,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,qDAAqD;SAC5F,CAAC;KACH,CAAC,CAAC;IACH,OAAO,IAAI,eAAe,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;AACjH,CAAC"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * The test-facing seam of the harness contract kit.
3
+ *
4
+ * `HarnessAdapter.runTurn(input, sink)` gives a test no way to make the
5
+ * engine DO anything: propose a gated action, emit usage, hang, fail. The
6
+ * approval-contract kit met the same problem with `GatewaySubstrate` — a
7
+ * small interface each real substrate adapts so one invariant catalog can
8
+ * drive all of them. This is that seam for harnesses: a
9
+ * {@link HarnessContractSubject} owns the ENGINE (what the next turn will
10
+ * do), and the kit owns everything the runtime would own (the sink, the
11
+ * `TurnInput`, the state id threading, the reinvocation).
12
+ *
13
+ * The scenario vocabulary is deliberately small and engine-neutral: it says
14
+ * what the kit needs to PROVOKE, never how an engine behaves. The scripted
15
+ * fake consumes it directly; a real harness's subject translates it onto that
16
+ * harness's own double (the Cursor subject onto the scripted `@cursor/sdk`
17
+ * agent of `execute-cursor/__test-utils__/`). One vocabulary, not one per
18
+ * engine, so the kit cannot drift from what the fake can do.
19
+ *
20
+ * Gated actions reuse `ProposedAction` from `approval-contract/types.ts`, the
21
+ * taxonomy-free action every enforcement substrate already translates, so the
22
+ * two kits speak of the same logical side effect and neither restates the
23
+ * HITL taxonomy.
24
+ */
25
+ import type { ApprovalAction } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
26
+ import type { Config } from "../../config.js";
27
+ import type { HarnessName } from "../../harness/registry.js";
28
+ import type { FailureSurface, HarnessAdapter, UsageDelta } from "../../harness/types.js";
29
+ import type { ProposedAction } from "../approval-contract/types.js";
30
+ import type { TurnInputFixtureOverrides } from "../turn-input-fixture.js";
31
+ /**
32
+ * One thing the engine does during a turn. A turn plays its steps in order
33
+ * and ends `completed` when none is left, unless a step ends it first.
34
+ *
35
+ * - `say`: the engine emits assistant text (a transcript row).
36
+ * - `propose`: the engine reaches a gated side effect identified by
37
+ * `toolCallId`. Undecided → the turn ends `awaiting_approval` and later
38
+ * steps do not run; APPROVE → the effect runs once and the turn continues;
39
+ * REJECT / SKIP → the effect never runs and the turn continues. WHICH
40
+ * kinds a harness gates is the harness's policy and the workspace's
41
+ * posture: a `shell` is gated by every harness in every posture; a `write`
42
+ * is gated only outside apply-then-review capture (a git tree, or artifact
43
+ * storage), so an arm that must gate on every subject proposes a `shell`.
44
+ * - `read`: the engine performs an UNGATED read of `path` — a tool-call row
45
+ * that runs at once, never pauses, and is the discrete event every harness
46
+ * flushes a persist on (the lever an arm pulls when it needs the control
47
+ * plane to answer a mid-turn persist).
48
+ * - `usage`: the engine reports one turn's token counts.
49
+ * - `hang`: the engine makes no further progress until told to stop. The
50
+ * step that the stop-signal invariants and the runtime's stall watchdog
51
+ * are built around; it must be parked on the signal, never on a timer.
52
+ * - `fail`: the engine fails with a message the adapter can name; the turn
53
+ * ends `failed` on the given surface (`engine` unless the scenario says
54
+ * otherwise — the runtime's three failure copies are its own invariant).
55
+ * - `cancelled`: the engine ends its own run cancelled with nothing to
56
+ * wait for (an SDK-side cancel); the turn ends `cancelled`.
57
+ */
58
+ export type ScenarioStep = {
59
+ readonly kind: "say";
60
+ readonly text: string;
61
+ } | {
62
+ readonly kind: "propose";
63
+ readonly toolCallId: string;
64
+ readonly action: ProposedAction;
65
+ } | {
66
+ readonly kind: "read";
67
+ readonly toolCallId: string;
68
+ readonly path: string;
69
+ } | {
70
+ readonly kind: "usage";
71
+ readonly delta: UsageDelta;
72
+ } | {
73
+ readonly kind: "hang";
74
+ } | {
75
+ readonly kind: "fail";
76
+ readonly message: string;
77
+ readonly surface: FailureSurface;
78
+ } | {
79
+ readonly kind: "cancelled";
80
+ };
81
+ /** One turn's worth of engine behaviour. */
82
+ export type TurnScenario = readonly ScenarioStep[];
83
+ /** Step builders — the vocabulary a kit invariant reads as. */
84
+ export declare const scenario: {
85
+ readonly say: (text: string) => ScenarioStep;
86
+ readonly propose: (toolCallId: string, action: ProposedAction) => ScenarioStep;
87
+ readonly read: (toolCallId: string, path: string) => ScenarioStep;
88
+ readonly usage: (delta: UsageDelta) => ScenarioStep;
89
+ readonly hang: () => ScenarioStep;
90
+ readonly fail: (message: string, surface?: FailureSurface) => ScenarioStep;
91
+ readonly cancelled: () => ScenarioStep;
92
+ };
93
+ /**
94
+ * What the engine can know about the turn it is about to play, handed to the
95
+ * subject with every {@link HarnessContractSubject.arrange}: which execution
96
+ * and session it serves (a real engine is per session — its handle is parked
97
+ * under the session, its workspace and hook state live under the session —
98
+ * so a subject arranges THAT session's engine, never "the next turn"), and
99
+ * the approval decisions the prompt will carry (the runtime's
100
+ * `approvalDecisionsOf` over the persisted status — the one reader both
101
+ * drivers call). A subject whose engine cannot re-run a settled action, or
102
+ * whose model is told not to perform a skipped one, reads its decision here
103
+ * instead of parsing the prompt for it.
104
+ */
105
+ export interface EngineView {
106
+ readonly executionId: string;
107
+ readonly sessionId: string;
108
+ readonly approvalDecisions: ReadonlyMap<string, ApprovalAction>;
109
+ }
110
+ /**
111
+ * What a subject may say about the record its engine is handed, laid UNDER
112
+ * the driver's own facts: the five it threads (`executionId`, `threadId`,
113
+ * `turnSeq`, `sessionId`, `approvalDecisions`) and the persisted status it
114
+ * seeds are the kit's bookkeeping and never a subject's to state.
115
+ */
116
+ export type SubjectInputOverrides = Omit<TurnInputFixtureOverrides, "executionId" | "threadId" | "turnSeq" | "sessionId" | "approvalDecisions" | "persistedStatus">;
117
+ /**
118
+ * One adapter under test, with the engine controls the kit needs. Adapters
119
+ * translate scenarios into their own double's drives and report what the
120
+ * double observed; they never reimplement contract behaviour.
121
+ *
122
+ * The kit owns the adapter's lifetime: it boots the adapter before the first
123
+ * turn and shuts it down after the last (the registry boots every adapter
124
+ * before the worker polls, and a real adapter refuses a turn before boot).
125
+ * The exported assertion functions therefore REQUIRE a booted adapter.
126
+ */
127
+ export interface HarnessContractSubject {
128
+ /** Stable name, used in suite titles and every assertion message. */
129
+ readonly name: string;
130
+ /** The registry row this adapter fills; the runtime half selects the activity by it. */
131
+ readonly harness: HarnessName;
132
+ /** The adapter under test — the real implementation of the contract. */
133
+ readonly adapter: HarnessAdapter;
134
+ /** What `adapter.boot` needs. The subject knows its adapter's fields; the kit does not. */
135
+ readonly config: Config;
136
+ /**
137
+ * Arrange the engine so that the NEXT `runTurn` for `view.sessionId` plays
138
+ * `turn` — REPLACING whatever was arranged for that session and not yet
139
+ * played (a turn interrupted before its engine ran leaves no stale script
140
+ * behind). Called by the kit before every `runTurn`, including a
141
+ * reinvocation (the engine re-reaches the same gated call on resume, so the
142
+ * same proposal is arranged again).
143
+ */
144
+ arrange(turn: TurnScenario, view: EngineView): void;
145
+ /**
146
+ * What this engine needs the record to say beyond the driver's facts (the
147
+ * model the adapter validates, the workspace its gate installs into). A
148
+ * subject whose engine reads nothing of the record omits it.
149
+ */
150
+ inputOverrides?(view: EngineView): SubjectInputOverrides;
151
+ /**
152
+ * Resolves the next time a turn parks on a `hang` step — the moment the
153
+ * kit stops a turn from the outside, and the moment the runtime half
154
+ * delivers a cancellation, a drain or the clock tick that trips the stall
155
+ * watchdog. A real engine reaches its hang only after real setup (file
156
+ * writes, catalog fetches); a stop delivered any earlier would land in that
157
+ * setup and prove nothing about the hang. Never a timer.
158
+ */
159
+ whenHanging(): Promise<void>;
160
+ /**
161
+ * How many times the side effect behind `toolCallId` actually ran, as the
162
+ * subject's double observed it. The safety-critical observable; zero for an
163
+ * id the engine never reached.
164
+ */
165
+ executionCount(toolCallId: string): number;
166
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * The test-facing seam of the harness contract kit.
3
+ *
4
+ * `HarnessAdapter.runTurn(input, sink)` gives a test no way to make the
5
+ * engine DO anything: propose a gated action, emit usage, hang, fail. The
6
+ * approval-contract kit met the same problem with `GatewaySubstrate` — a
7
+ * small interface each real substrate adapts so one invariant catalog can
8
+ * drive all of them. This is that seam for harnesses: a
9
+ * {@link HarnessContractSubject} owns the ENGINE (what the next turn will
10
+ * do), and the kit owns everything the runtime would own (the sink, the
11
+ * `TurnInput`, the state id threading, the reinvocation).
12
+ *
13
+ * The scenario vocabulary is deliberately small and engine-neutral: it says
14
+ * what the kit needs to PROVOKE, never how an engine behaves. The scripted
15
+ * fake consumes it directly; a real harness's subject translates it onto that
16
+ * harness's own double (the Cursor subject onto the scripted `@cursor/sdk`
17
+ * agent of `execute-cursor/__test-utils__/`). One vocabulary, not one per
18
+ * engine, so the kit cannot drift from what the fake can do.
19
+ *
20
+ * Gated actions reuse `ProposedAction` from `approval-contract/types.ts`, the
21
+ * taxonomy-free action every enforcement substrate already translates, so the
22
+ * two kits speak of the same logical side effect and neither restates the
23
+ * HITL taxonomy.
24
+ */
25
+ /** Step builders — the vocabulary a kit invariant reads as. */
26
+ export const scenario = {
27
+ say(text) {
28
+ return { kind: "say", text };
29
+ },
30
+ propose(toolCallId, action) {
31
+ return { kind: "propose", toolCallId, action };
32
+ },
33
+ read(toolCallId, path) {
34
+ return { kind: "read", toolCallId, path };
35
+ },
36
+ usage(delta) {
37
+ return { kind: "usage", delta };
38
+ },
39
+ hang() {
40
+ return { kind: "hang" };
41
+ },
42
+ fail(message, surface = "engine") {
43
+ return { kind: "fail", message, surface };
44
+ },
45
+ cancelled() {
46
+ return { kind: "cancelled" };
47
+ },
48
+ };
49
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/__test-utils__/harness-contract/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAiDH,+DAA+D;AAC/D,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,GAAG,CAAC,IAAY;QACd,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAC/B,CAAC;IACD,OAAO,CAAC,UAAkB,EAAE,MAAsB;QAChD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;IACjD,CAAC;IACD,IAAI,CAAC,UAAkB,EAAE,IAAY;QACnC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IAC5C,CAAC;IACD,KAAK,CAAC,KAAiB;QACrB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAClC,CAAC;IACD,IAAI;QACF,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC;IACD,IAAI,CAAC,OAAe,EAAE,UAA0B,QAAQ;QACtD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAC5C,CAAC;IACD,SAAS;QACP,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAC/B,CAAC;CACO,CAAC"}
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Hermetic activity driver — run a REAL runner activity end to end with no
3
+ * network, no credentials, and no live Temporal worker, and read back every
4
+ * status it persisted.
5
+ *
6
+ * Why this exists: the runner's activities (`ExecuteCursor`, `ExecuteDeepAgent`)
7
+ * are the wire contract the control plane's workflow keys on — the phases they
8
+ * persist, the copy they write, whether they RETURN a slim status or THROW
9
+ * `CancelledFailure`. Refactoring them safely needs goldens recorded through the
10
+ * activity whole, not through its modules one at a time. The native harness
11
+ * tests already run their activity hermetically by mocking three modules at the
12
+ * boundary (`execute-deep-agent/__tests__/{index,hitl-*,sequential-gate-resume}.test.ts`);
13
+ * this module is that convention made reusable, harness-agnostic, and driven by
14
+ * the framework's own activity environment instead of a hand-written stand-in.
15
+ *
16
+ * What is generic here and what is not: everything an activity touches that is
17
+ * NOT the vendor SDK — the Temporal `Context`, the control-plane client, the
18
+ * runner-owned `~/.stigmer` tree, artifact storage, the model registry, the
19
+ * clock, the worker-shutdown signal — is set up here. The vendor SDK double
20
+ * belongs to the harness (`activities/execute-cursor/__test-utils__/scripted-*.ts`),
21
+ * the same split as `approval-contract/` (runner-wide kit) + each harness's
22
+ * `gateway-substrate.ts`.
23
+ *
24
+ * Three substitutions, and why each is shaped the way it is:
25
+ *
26
+ * 1. `Context.current()` — `MockActivityEnvironment` from `@temporalio/testing`,
27
+ * ONE PER INVOCATION. It gives the activity a real `Context` (real
28
+ * `cancellationSignal`, real `heartbeat()` surfaced as events, real
29
+ * `CancelledFailure` on throw). The native tests' stand-in mints a fresh
30
+ * `AbortController` on every `Context.current()` call and so cannot drive a
31
+ * pause; production hands each attempt one `Context`, and so does this. The
32
+ * environment's documented caveat — once cancelled it stays cancelled — is
33
+ * why it is per invocation and never shared.
34
+ *
35
+ * 2. `StigmerClient` — the test file mocks the module (`vi.mock` is hoisted and
36
+ * must live in the test file; see {@link hermeticStigmerClientModule}) and
37
+ * the constructor hands back whatever client {@link bindHermeticClient} bound
38
+ * for the current run. The client is `mockStigmerClient` over an
39
+ * {@link ExecutionRecord}: `updateStatus` writes back into the record the way
40
+ * the server would, so a REINVOCATION (`threadId` set) reads the transcript
41
+ * the first invocation persisted — the resume path runs on real data, not on
42
+ * a hand-built status.
43
+ *
44
+ * 3. The environment — a temp `HOME` (the runner-owned `~/.stigmer` tree,
45
+ * `platform-dir.ts` reads `process.env.HOME`), a temp workspace root, local
46
+ * artifact storage in a temp dir, and the HITL fingerprint secret pinned by
47
+ * env var (`fingerprint-secret.ts` falls back to `randomBytes` — the ONE
48
+ * source of randomness on the activity path — and memoizes on first call, so
49
+ * the pin must precede the first invocation in the process).
50
+ *
51
+ * Determinism: the clock is faked for `Date` ONLY (`vi.useFakeTimers({ toFake:
52
+ * ["Date"] })`) and TICKS — the harness double advances it a fixed quantum per
53
+ * script step through {@link ScriptedClock}. Frozen time would make
54
+ * `delta-enricher.ts`'s persist debounce (`Date.now() - lastPersistTime`) never
55
+ * elapse and silently skip the mid-stream persist path production always runs;
56
+ * a ticking clock runs the same path and lands on the same instants every run.
57
+ * Timers stay real so the periodic heartbeat and the stall watchdog behave.
58
+ *
59
+ * Not in scope: this module never edits a production module and never
60
+ * normalizes output. If a golden is not byte-stable, the volatile source is
61
+ * controlled at its origin or the surprise is escalated — never redacted here.
62
+ */
63
+ import { CancelledFailure } from "@temporalio/activity";
64
+ import { type AgentExecution, type AgentExecutionStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
65
+ import { ApprovalAction, ExecutionControlSignal, ExecutionPhase } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
66
+ import type { ToolCall } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
67
+ import { type Session } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
68
+ import type { Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
69
+ import type { AgentInstance } from "@stigmer/protos/ai/stigmer/agentic/agentinstance/v1/api_pb";
70
+ import type { StigmerClient } from "../client/stigmer-client.js";
71
+ /**
72
+ * The four resources the activity's blueprint chain reads
73
+ * (`execution.spec.sessionId -> session.spec.agentInstanceId ->
74
+ * agentInstance.spec.agentId -> agent`) plus the status the server would hold.
75
+ */
76
+ export interface ExecutionRecordInput {
77
+ readonly execution: AgentExecution;
78
+ readonly session: Session;
79
+ readonly agentInstance: AgentInstance;
80
+ readonly agent: Agent;
81
+ /**
82
+ * What `UpdateStatus` answers for each FULL status write — the platform's
83
+ * STOP lever (`ExecutionControlSignal`), decided by the control plane per
84
+ * write and read by the harness stream loop on its mid-stream persist.
85
+ * Evaluated AFTER the write lands, on the snapshot just persisted, so a
86
+ * policy can key on the transcript ("stop once the first assistant message
87
+ * is in"). Defaults to UNSPECIFIED: keep going.
88
+ */
89
+ readonly controlSignal?: (status: AgentExecutionStatus) => ExecutionControlSignal;
90
+ }
91
+ /**
92
+ * An in-memory stand-in for the server's execution row, with the TWO merge
93
+ * rules and the ONE control lever the activity depends on, and no others:
94
+ *
95
+ * - A status whose phase is UNSPECIFIED is a setup-progress report
96
+ * (`reportSetupProgress`): the server keeps `setup_progress` and leaves the
97
+ * phase and transcript alone. Modelled as: record the label, change nothing else.
98
+ * - Any other status replaces the held status wholesale (the runner is the
99
+ * writer of the transcript; the server's own field-ownership merge — approval
100
+ * fields it owns — is exercised by the test SETTING `approvalAction` on the
101
+ * record between invocations, exactly as `SubmitApproval` would).
102
+ * - Every `UpdateStatus` answers a control signal ({@link ExecutionRecordInput.controlSignal});
103
+ * the server's STOP is the one instruction that travels back to the runner
104
+ * on this channel, and it is a server decision, so it is modelled here and
105
+ * not by the test hand-writing the client.
106
+ *
107
+ * Every persisted status is also kept in order (`persisted`) so a test can
108
+ * assert the phase sequence the activity wrote, independent of the final state.
109
+ */
110
+ export declare class ExecutionRecord {
111
+ readonly execution: AgentExecution;
112
+ readonly session: Session;
113
+ readonly agentInstance: AgentInstance;
114
+ readonly agent: Agent;
115
+ private readonly controlSignal;
116
+ /** Every `updateStatus` payload, in order, snapshotted at write time. */
117
+ readonly persisted: AgentExecutionStatus[];
118
+ /** Setup-progress labels reported before the stream started, in order. */
119
+ readonly setupProgress: string[];
120
+ /**
121
+ * Every `updateSession` payload, in order (the `harness_state_id` write-back),
122
+ * snapshotted at write time: the activity re-binds the SAME session object on
123
+ * a fresh-agent recovery, so a live reference would show the second id twice.
124
+ */
125
+ readonly sessionUpdates: Session[];
126
+ constructor(input: ExecutionRecordInput);
127
+ get executionId(): string;
128
+ /** The status the server would currently hold (what `getExecution` returns). */
129
+ get status(): AgentExecutionStatus | undefined;
130
+ /** The last FULL status written (phase set), or undefined if none yet. */
131
+ get lastFullStatus(): AgentExecutionStatus | undefined;
132
+ /**
133
+ * The ORDERED, DISTINCT phases the activity persisted — the deterministic
134
+ * shape of the persist cadence. The COUNT of persists depends on the
135
+ * debounce timer and is deliberately not exposed as an assertion surface.
136
+ */
137
+ get persistedPhases(): ExecutionPhase[];
138
+ /** Every tool call on the held transcript (top-level messages), in order. */
139
+ toolCalls(): ToolCall[];
140
+ /** The tool calls currently paused for a decision. */
141
+ waitingToolCalls(): ToolCall[];
142
+ /**
143
+ * What the server's `SubmitApproval` does to the row: record the decision on
144
+ * the tool call the runner wrote. The runner owns `status`; the server owns
145
+ * `approval_action` (field ownership, 005 mandate 2) — so this is the ONE
146
+ * place a test writes it, and the status stays WAITING_APPROVAL until the
147
+ * resumed turn runs the tool, exactly as in production.
148
+ */
149
+ decideWaitingToolCalls(action: ApprovalAction, decidedAt: string): number;
150
+ /**
151
+ * Apply one `UpdateStatus` write and answer the control signal the server
152
+ * would. A setup-progress report never carries a signal (the runner ignores
153
+ * the response there; the server has nothing to say about a label).
154
+ */
155
+ applyStatusUpdate(status: AgentExecutionStatus): ExecutionControlSignal;
156
+ /**
157
+ * The control-plane client the activity sees: every read answers from this
158
+ * record; every write lands in it. Reads the activity makes for optional
159
+ * facets (execution context, channels, skills) answer the everyday shape —
160
+ * NOT_FOUND for the execution context (an execution with no env vars), no
161
+ * channels, no scoped token (the OSS/local posture) — so a scenario opts INTO
162
+ * a facet by overriding.
163
+ */
164
+ client(overrides?: Partial<StigmerClient>): StigmerClient;
165
+ }
166
+ /**
167
+ * Bind the client the mocked `StigmerClient` constructor hands out for the
168
+ * current run. Called by the harness driver immediately before invoking the
169
+ * activity factory (`createCursorActivities(config)` constructs its client
170
+ * inside the factory, so the bind must precede the factory call).
171
+ */
172
+ export declare function bindHermeticClient(client: StigmerClient): void;
173
+ /**
174
+ * The factory a test passes to `vi.mock(".../client/stigmer-client.js", ...)`.
175
+ * `vi.mock` is hoisted and must appear in the test file itself; the factory can
176
+ * `await import()` this module. Usage:
177
+ *
178
+ * ```ts
179
+ * vi.mock("../../../../client/stigmer-client.js", async () =>
180
+ * (await import("../../../../__test-utils__/hermetic-activity.js")).hermeticStigmerClientModule(),
181
+ * );
182
+ * ```
183
+ */
184
+ export declare function hermeticStigmerClientModule(): {
185
+ StigmerClient: new () => StigmerClient;
186
+ };
187
+ export interface HermeticEnvironment {
188
+ /** The temp `HOME` (the runner's `~/.stigmer` lands under it). */
189
+ readonly home: string;
190
+ /** The temp workspace root (`config.workspaceRootDir`). */
191
+ readonly workspaceRootDir: string;
192
+ /** The temp local artifact store (`LOCAL_ARTIFACT_PATH`). */
193
+ readonly artifactPath: string;
194
+ /** Restore every env var and remove the temp tree. Idempotent. */
195
+ dispose(): void;
196
+ }
197
+ /**
198
+ * Create the temp tree and pin the env vars. Call once per test FILE (in
199
+ * `beforeAll`) — the fingerprint secret is memoized per process on first use,
200
+ * and vitest isolates files in forks, so per-file is the natural unit.
201
+ */
202
+ export declare function createHermeticEnvironment(): HermeticEnvironment;
203
+ /**
204
+ * A deterministic, TICKING `Date`. Only `Date` is faked; timers stay real (the
205
+ * periodic heartbeat, the stall watchdog, `withTimeout` all need them). The
206
+ * harness double calls {@link ScriptedClock.tick} once per script step, so
207
+ * every `Date.now()`-based decision on the activity path (status timestamps,
208
+ * the enricher's persist debounce, cache TTLs) sees the same instants run after
209
+ * run and runs the same branches production runs.
210
+ */
211
+ export declare class ScriptedClock {
212
+ /** A fixed epoch: 2026-01-01T00:00:00.000Z. Chosen for readability in goldens. */
213
+ static readonly EPOCH_MS: number;
214
+ /** One second per step — well under any stall or cache horizon. */
215
+ static readonly STEP_MS = 1000;
216
+ private nowMs;
217
+ install(): void;
218
+ tick(ms?: number): void;
219
+ /** Back to the epoch — for a second scenario in the same file. */
220
+ reset(): void;
221
+ uninstall(): void;
222
+ }
223
+ /** How an activity invocation ended: the return value or the error it threw. */
224
+ export type ActivityOutcome = {
225
+ readonly kind: "returned";
226
+ readonly value: unknown;
227
+ } | {
228
+ readonly kind: "threw";
229
+ readonly error: unknown;
230
+ };
231
+ export interface ActivityInvocation {
232
+ readonly outcome: ActivityOutcome;
233
+ /** Heartbeat details the activity reported, in order. */
234
+ readonly heartbeats: unknown[];
235
+ /** The `taskQueue` the invocation ran on (the shutdown signal is keyed by it). */
236
+ readonly taskQueue: string;
237
+ }
238
+ /**
239
+ * Handles a scenario uses to interrupt the invocation FROM A SCRIPT STEP —
240
+ * never from a timer. `cancel()` aborts the activity's `cancellationSignal`
241
+ * (a user pause, as the workflow delivers it). `signalWorkerShutdown()` aborts
242
+ * the queue's shutdown signal first, which the activity reads to tell a worker
243
+ * drain from a user pause (`classifyTurnInterruption`).
244
+ */
245
+ export interface InvocationControls {
246
+ cancel(): void;
247
+ signalWorkerShutdown(): void;
248
+ }
249
+ export interface RunActivityOptions {
250
+ readonly taskQueue?: string;
251
+ /**
252
+ * Receives the invocation's controls before the activity starts, so a
253
+ * scenario can hand them to the harness double's `effect` steps.
254
+ */
255
+ readonly onControls?: (controls: InvocationControls) => void;
256
+ }
257
+ /**
258
+ * Run one activity function under a fresh `MockActivityEnvironment` and
259
+ * capture how it ended. `CancelledFailure` is caught like any other throw and
260
+ * reported as `{ kind: "threw" }` — the throw-vs-return table is the thing
261
+ * under test, so the driver never interprets it.
262
+ */
263
+ export declare function runActivityHermetically<A extends unknown[]>(activity: (...args: A) => Promise<unknown>, args: A, options?: RunActivityOptions): Promise<ActivityInvocation>;
264
+ /** True when the outcome is a thrown Temporal `CancelledFailure`. */
265
+ export declare function threwCancelledFailure(outcome: ActivityOutcome): outcome is {
266
+ kind: "threw";
267
+ error: CancelledFailure;
268
+ };