@stigmer/runner 3.14.1 → 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 (320) 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 +28 -5
  9. package/dist/__test-utils__/hermetic-activity.js +23 -7
  10. package/dist/__test-utils__/hermetic-activity.js.map +1 -1
  11. package/dist/__test-utils__/mock-workspace.d.ts +15 -0
  12. package/dist/__test-utils__/mock-workspace.js +21 -0
  13. package/dist/__test-utils__/mock-workspace.js.map +1 -0
  14. package/dist/__test-utils__/model-registry-fixture.d.ts +56 -0
  15. package/dist/__test-utils__/model-registry-fixture.js +66 -0
  16. package/dist/__test-utils__/model-registry-fixture.js.map +1 -0
  17. package/dist/__test-utils__/turn-input-fixture.d.ts +60 -0
  18. package/dist/__test-utils__/turn-input-fixture.js +118 -0
  19. package/dist/__test-utils__/turn-input-fixture.js.map +1 -0
  20. package/dist/activities/execute-cursor/__test-utils__/contract-subject.d.ts +107 -0
  21. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js +344 -0
  22. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js.map +1 -0
  23. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.d.ts +20 -0
  24. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js +58 -0
  25. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js.map +1 -1
  26. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js +2 -32
  27. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js.map +1 -1
  28. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +38 -62
  29. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +47 -121
  30. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
  31. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.d.ts +17 -1
  32. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js +27 -4
  33. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js.map +1 -1
  34. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.d.ts +52 -11
  35. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js +66 -7
  36. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js.map +1 -1
  37. package/dist/activities/execute-cursor/adapter.d.ts +55 -0
  38. package/dist/activities/execute-cursor/adapter.js +119 -0
  39. package/dist/activities/execute-cursor/adapter.js.map +1 -0
  40. package/dist/activities/execute-cursor/approval-state.d.ts +2 -2
  41. package/dist/activities/execute-cursor/approval-state.js.map +1 -1
  42. package/dist/activities/execute-cursor/capture-flow.d.ts +15 -30
  43. package/dist/activities/execute-cursor/capture-flow.js +17 -26
  44. package/dist/activities/execute-cursor/capture-flow.js.map +1 -1
  45. package/dist/activities/execute-cursor/cursor-capabilities.d.ts +23 -0
  46. package/dist/activities/execute-cursor/cursor-capabilities.js +33 -0
  47. package/dist/activities/execute-cursor/cursor-capabilities.js.map +1 -0
  48. package/dist/activities/execute-cursor/cursor-mcp-config.d.ts +2 -2
  49. package/dist/activities/execute-cursor/cursor-mcp-config.js.map +1 -1
  50. package/dist/activities/execute-cursor/fetch-interceptor.d.ts +15 -25
  51. package/dist/activities/execute-cursor/fetch-interceptor.js +39 -33
  52. package/dist/activities/execute-cursor/fetch-interceptor.js.map +1 -1
  53. package/dist/activities/execute-cursor/http2-interceptor.d.ts +21 -17
  54. package/dist/activities/execute-cursor/http2-interceptor.js +38 -31
  55. package/dist/activities/execute-cursor/http2-interceptor.js.map +1 -1
  56. package/dist/activities/execute-cursor/message-translator.d.ts +28 -19
  57. package/dist/activities/execute-cursor/message-translator.js +76 -27
  58. package/dist/activities/execute-cursor/message-translator.js.map +1 -1
  59. package/dist/activities/execute-cursor/prompt-builder.d.ts +180 -11
  60. package/dist/activities/execute-cursor/prompt-builder.js +171 -0
  61. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  62. package/dist/activities/execute-cursor/rejection-capture.d.ts +3 -6
  63. package/dist/activities/execute-cursor/rejection-capture.js +5 -7
  64. package/dist/activities/execute-cursor/rejection-capture.js.map +1 -1
  65. package/dist/activities/execute-cursor/session-lifecycle.d.ts +1 -4
  66. package/dist/activities/execute-cursor/session-lifecycle.js.map +1 -1
  67. package/dist/activities/execute-cursor/turn-boundary.d.ts +1 -1
  68. package/dist/activities/execute-cursor/turn-settle.d.ts +49 -0
  69. package/dist/activities/execute-cursor/turn-settle.js +507 -0
  70. package/dist/activities/execute-cursor/turn-settle.js.map +1 -0
  71. package/dist/activities/execute-cursor/turn-setup.d.ts +173 -0
  72. package/dist/activities/execute-cursor/turn-setup.js +496 -0
  73. package/dist/activities/execute-cursor/turn-setup.js.map +1 -0
  74. package/dist/activities/execute-cursor/turn-stream.d.ts +41 -71
  75. package/dist/activities/execute-cursor/turn-stream.js +70 -135
  76. package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
  77. package/dist/activities/execute-cursor/turn.d.ts +43 -0
  78. package/dist/activities/execute-cursor/turn.js +222 -0
  79. package/dist/activities/execute-cursor/turn.js.map +1 -0
  80. package/dist/activities/execute-cursor/usage-pricing.d.ts +38 -0
  81. package/dist/activities/execute-cursor/usage-pricing.js +50 -0
  82. package/dist/activities/execute-cursor/usage-pricing.js.map +1 -0
  83. package/dist/activities/execute-deep-agent/approval-file-change.d.ts +1 -1
  84. package/dist/activities/execute-deep-agent/approval-file-change.js +1 -1
  85. package/dist/activities/execute-deep-agent/environment.js +1 -1
  86. package/dist/activities/execute-deep-agent/environment.js.map +1 -1
  87. package/dist/activities/execute-deep-agent/setup.js +3 -2
  88. package/dist/activities/execute-deep-agent/setup.js.map +1 -1
  89. package/dist/activities/hydrate-workflow-execution.js +1 -1
  90. package/dist/activities/hydrate-workflow-execution.js.map +1 -1
  91. package/dist/config.d.ts +15 -0
  92. package/dist/config.js.map +1 -1
  93. package/dist/harness/capabilities.d.ts +16 -0
  94. package/dist/harness/capabilities.js +1 -0
  95. package/dist/harness/capabilities.js.map +1 -1
  96. package/dist/harness/persist-chokepoint.d.ts +74 -0
  97. package/dist/harness/persist-chokepoint.js +88 -0
  98. package/dist/harness/persist-chokepoint.js.map +1 -0
  99. package/dist/harness/registry.d.ts +44 -5
  100. package/dist/harness/registry.js +61 -5
  101. package/dist/harness/registry.js.map +1 -1
  102. package/dist/harness/run-turn.d.ts +53 -0
  103. package/dist/harness/run-turn.js +528 -0
  104. package/dist/harness/run-turn.js.map +1 -0
  105. package/dist/harness/stop-controller.d.ts +50 -0
  106. package/dist/harness/stop-controller.js +62 -0
  107. package/dist/harness/stop-controller.js.map +1 -0
  108. package/dist/harness/terminal-table.d.ts +141 -0
  109. package/dist/harness/terminal-table.js +239 -0
  110. package/dist/harness/terminal-table.js.map +1 -0
  111. package/dist/harness/turn-context.d.ts +523 -0
  112. package/dist/harness/turn-context.js +739 -0
  113. package/dist/harness/turn-context.js.map +1 -0
  114. package/dist/harness/types.d.ts +232 -52
  115. package/dist/harness/types.js +17 -8
  116. package/dist/harness/types.js.map +1 -1
  117. package/dist/harness/usage-accumulator.d.ts +68 -0
  118. package/dist/harness/usage-accumulator.js +101 -0
  119. package/dist/harness/usage-accumulator.js.map +1 -0
  120. package/dist/harness-adapters.d.ts +27 -0
  121. package/dist/harness-adapters.js +28 -0
  122. package/dist/harness-adapters.js.map +1 -0
  123. package/dist/main.js.map +1 -1
  124. package/dist/runner-manager.js +64 -48
  125. package/dist/runner-manager.js.map +1 -1
  126. package/dist/runner.d.ts +5 -4
  127. package/dist/runner.js +65 -64
  128. package/dist/runner.js.map +1 -1
  129. package/dist/shared/approval-policy.d.ts +1 -1
  130. package/dist/shared/approval-policy.js.map +1 -1
  131. package/dist/{activities/execute-cursor → shared}/attachment-resolver.d.ts +2 -2
  132. package/dist/{activities/execute-cursor → shared}/attachment-resolver.js +5 -5
  133. package/dist/shared/attachment-resolver.js.map +1 -0
  134. package/dist/{activities/execute-cursor → shared}/blueprint-resolver.d.ts +7 -5
  135. package/dist/{activities/execute-cursor → shared}/blueprint-resolver.js +3 -63
  136. package/dist/shared/blueprint-resolver.js.map +1 -0
  137. package/dist/shared/channel-attachment.d.ts +1 -1
  138. package/dist/shared/channel-attachment.js.map +1 -1
  139. package/dist/{activities/execute-cursor → shared}/cost-guard.d.ts +5 -1
  140. package/dist/{activities/execute-cursor → shared}/cost-guard.js +5 -1
  141. package/dist/shared/cost-guard.js.map +1 -0
  142. package/dist/{activities/execute-cursor → shared}/env-resolver.d.ts +1 -1
  143. package/dist/shared/env-resolver.js.map +1 -0
  144. package/dist/{activities/execute-cursor → shared}/exact-apply.d.ts +1 -1
  145. package/dist/{activities/execute-cursor → shared}/exact-apply.js +6 -6
  146. package/dist/shared/exact-apply.js.map +1 -0
  147. package/dist/shared/execution-context.d.ts +35 -0
  148. package/dist/shared/execution-context.js +38 -0
  149. package/dist/shared/execution-context.js.map +1 -0
  150. package/dist/{activities/execute-cursor → shared}/extract-structured-output.d.ts +5 -2
  151. package/dist/{activities/execute-cursor → shared}/extract-structured-output.js +9 -6
  152. package/dist/shared/extract-structured-output.js.map +1 -0
  153. package/dist/shared/filereview/capture.d.ts +1 -1
  154. package/dist/shared/filereview/capture.js +1 -1
  155. package/dist/shared/heartbeat.d.ts +13 -11
  156. package/dist/shared/heartbeat.js +14 -29
  157. package/dist/shared/heartbeat.js.map +1 -1
  158. package/dist/{activities/execute-cursor → shared}/persist-decision.d.ts +5 -2
  159. package/dist/{activities/execute-cursor → shared}/persist-decision.js +4 -1
  160. package/dist/shared/persist-decision.js.map +1 -0
  161. package/dist/{activities/execute-cursor → shared}/skill-resolver.d.ts +16 -3
  162. package/dist/{activities/execute-cursor → shared}/skill-resolver.js +12 -4
  163. package/dist/shared/skill-resolver.js.map +1 -0
  164. package/dist/shared/subagent-rows.d.ts +21 -0
  165. package/dist/shared/subagent-rows.js +34 -0
  166. package/dist/shared/subagent-rows.js.map +1 -0
  167. package/dist/shared/worker-shutdown.d.ts +43 -16
  168. package/dist/shared/worker-shutdown.js +28 -13
  169. package/dist/shared/worker-shutdown.js.map +1 -1
  170. package/dist/shared/workspace/platform-dir.d.ts +1 -1
  171. package/dist/shared/workspace/platform-dir.js +1 -1
  172. package/dist/shared/workspace/session-provision.d.ts +54 -0
  173. package/dist/{activities/execute-cursor/workspace-provision.js → shared/workspace/session-provision.js} +15 -12
  174. package/dist/shared/workspace/session-provision.js.map +1 -0
  175. package/package.json +4 -4
  176. package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +110 -14
  177. package/src/__test-utils__/execution-record-fixture.ts +104 -0
  178. package/src/__test-utils__/harness-boot-order-child.ts +58 -0
  179. package/src/__test-utils__/harness-contract/contract.ts +128 -83
  180. package/src/__test-utils__/harness-contract/recording-sink.ts +15 -4
  181. package/src/__test-utils__/harness-contract/runtime-contract.ts +666 -0
  182. package/src/__test-utils__/harness-contract/scripted-adapter.ts +92 -32
  183. package/src/__test-utils__/harness-contract/types.ts +85 -9
  184. package/src/__test-utils__/hermetic-activity.ts +33 -8
  185. package/src/__test-utils__/model-registry-fixture.ts +72 -0
  186. package/src/__test-utils__/module-specifiers.ts +82 -0
  187. package/src/__test-utils__/turn-input-fixture.ts +155 -0
  188. package/src/__tests__/harness-boot-order.test.ts +77 -0
  189. package/src/__tests__/harness-contract.test.ts +7 -5
  190. package/src/__tests__/runner-manager.test.ts +18 -0
  191. package/src/activities/execute-cursor/__test-utils__/__tests__/scripted-double.test.ts +102 -0
  192. package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +396 -0
  193. package/src/activities/execute-cursor/__test-utils__/cursor-hook-harness.ts +66 -0
  194. package/src/activities/execute-cursor/__test-utils__/gateway-substrate.ts +2 -43
  195. package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +65 -145
  196. package/src/activities/execute-cursor/__test-utils__/scripted-agent.ts +30 -4
  197. package/src/activities/execute-cursor/__test-utils__/scripted-sdk.ts +96 -8
  198. package/src/activities/execute-cursor/__tests__/adapter-is-temporal-free.test.ts +45 -0
  199. package/src/activities/execute-cursor/__tests__/approval-decisions-agree.test.ts +90 -0
  200. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +7 -8
  201. package/src/activities/execute-cursor/__tests__/capture-flow.test.ts +28 -1
  202. package/src/activities/execute-cursor/__tests__/deny-gate-exact-apply.test.ts +1 -1
  203. package/src/activities/execute-cursor/__tests__/fetch-interceptor.test.ts +64 -6
  204. package/src/activities/execute-cursor/__tests__/hermetic/deny-and-retry.test.ts +1 -1
  205. package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +1 -1
  206. package/src/activities/execute-cursor/__tests__/hermetic/goldens/cost-cap.status.json +53 -0
  207. package/src/activities/execute-cursor/__tests__/hermetic/goldens/pause.status.json +1 -6
  208. package/src/activities/execute-cursor/__tests__/hermetic/goldens/platform-stop.status.json +56 -0
  209. package/src/activities/execute-cursor/__tests__/hermetic/goldens/recovery-transport-timeout.status.json +48 -0
  210. package/src/activities/execute-cursor/__tests__/hermetic/goldens/resolution-error.status.json +18 -0
  211. package/src/activities/execute-cursor/__tests__/hermetic/goldens/run-cancelled.status.json +36 -0
  212. package/src/activities/execute-cursor/__tests__/hermetic/goldens/run-error-non-retryable.status.json +37 -0
  213. package/src/activities/execute-cursor/__tests__/hermetic/goldens/sdk-error-at-create.status.json +38 -0
  214. package/src/activities/execute-cursor/__tests__/hermetic/goldens/stall.status.json +59 -0
  215. package/src/activities/execute-cursor/__tests__/hermetic/goldens/unattributed-hook-block.status.json +79 -0
  216. package/src/activities/execute-cursor/__tests__/hermetic/goldens/worker-shutdown.status.json +2 -7
  217. package/src/activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts +170 -0
  218. package/src/activities/execute-cursor/__tests__/hermetic/pause-vs-shutdown.test.ts +22 -18
  219. package/src/activities/execute-cursor/__tests__/hermetic/plain-turn.test.ts +1 -1
  220. package/src/activities/execute-cursor/__tests__/hermetic/recovery-fresh-agent.test.ts +1 -1
  221. package/src/activities/execute-cursor/__tests__/hermetic/run-wait-arms.test.ts +286 -0
  222. package/src/activities/execute-cursor/__tests__/hermetic/stream-self-stop-arms.test.ts +332 -0
  223. package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +193 -0
  224. package/src/activities/execute-cursor/__tests__/hermetic/tool-call.test.ts +1 -1
  225. package/src/activities/execute-cursor/__tests__/hermetic/unattributed-hook-block.test.ts +185 -0
  226. package/src/activities/execute-cursor/__tests__/hermetic/workspace-lock-timeout.test.ts +151 -0
  227. package/src/activities/execute-cursor/__tests__/http2-interceptor.test.ts +65 -35
  228. package/src/activities/execute-cursor/__tests__/message-translator.test.ts +0 -40
  229. package/src/activities/execute-cursor/__tests__/same-identity-reproposal.test.ts +171 -0
  230. package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +118 -243
  231. package/src/activities/execute-cursor/__tests__/usage-pricing.test.ts +84 -0
  232. package/src/activities/execute-cursor/adapter.ts +138 -0
  233. package/src/activities/execute-cursor/approval-state.ts +2 -2
  234. package/src/activities/execute-cursor/capture-flow.ts +18 -41
  235. package/src/activities/execute-cursor/cursor-capabilities.ts +35 -0
  236. package/src/activities/execute-cursor/cursor-mcp-config.ts +2 -2
  237. package/src/activities/execute-cursor/fetch-interceptor.ts +48 -45
  238. package/src/activities/execute-cursor/http2-interceptor.ts +47 -34
  239. package/src/activities/execute-cursor/message-translator.ts +90 -45
  240. package/src/activities/execute-cursor/prompt-builder.ts +327 -12
  241. package/src/activities/execute-cursor/rejection-capture.ts +5 -12
  242. package/src/activities/execute-cursor/session-lifecycle.ts +1 -5
  243. package/src/activities/execute-cursor/turn-boundary.ts +1 -1
  244. package/src/activities/execute-cursor/turn-settle.ts +601 -0
  245. package/src/activities/execute-cursor/turn-setup.ts +645 -0
  246. package/src/activities/execute-cursor/turn-stream.ts +84 -210
  247. package/src/activities/execute-cursor/turn.ts +240 -0
  248. package/src/activities/execute-cursor/usage-pricing.ts +67 -0
  249. package/src/activities/execute-deep-agent/approval-file-change.ts +1 -1
  250. package/src/activities/execute-deep-agent/environment.ts +1 -1
  251. package/src/activities/execute-deep-agent/setup.ts +3 -2
  252. package/src/activities/hydrate-workflow-execution.ts +1 -1
  253. package/src/config.ts +13 -0
  254. package/src/harness/__tests__/import-direction.test.ts +168 -0
  255. package/src/harness/__tests__/persist-chokepoint.test.ts +146 -0
  256. package/src/harness/__tests__/registry.test.ts +1 -0
  257. package/src/harness/__tests__/run-turn.test.ts +165 -0
  258. package/src/harness/__tests__/stop-controller.test.ts +49 -0
  259. package/src/harness/__tests__/turn-context.test.ts +178 -0
  260. package/src/harness/__tests__/usage-accumulator.test.ts +83 -0
  261. package/src/harness/capabilities.ts +17 -0
  262. package/src/harness/persist-chokepoint.ts +112 -0
  263. package/src/harness/registry.ts +79 -5
  264. package/src/harness/run-turn.ts +618 -0
  265. package/src/harness/stop-controller.ts +83 -0
  266. package/src/harness/terminal-table.ts +276 -0
  267. package/src/harness/turn-context.ts +1028 -0
  268. package/src/harness/types.ts +248 -53
  269. package/src/harness/usage-accumulator.ts +122 -0
  270. package/src/harness-adapters.ts +30 -0
  271. package/src/main.ts +1 -1
  272. package/src/runner-manager.ts +68 -61
  273. package/src/runner.ts +67 -78
  274. package/src/shared/__tests__/attachment-naming.test.ts +1 -1
  275. package/src/{activities/execute-cursor → shared}/__tests__/attachment-resolver.test.ts +6 -4
  276. package/src/{activities/execute-cursor → shared}/__tests__/cost-guard.test.ts +2 -1
  277. package/src/{activities/execute-cursor → shared}/__tests__/exact-apply.test.ts +3 -3
  278. package/src/{activities/execute-cursor → shared}/__tests__/extract-structured-output.test.ts +8 -8
  279. package/src/{activities/execute-cursor → shared}/__tests__/persist-decision.test.ts +4 -2
  280. package/src/{activities/execute-cursor → shared}/__tests__/skill-resolver.test.ts +1 -1
  281. package/src/shared/__tests__/subagent-rows.test.ts +34 -0
  282. package/src/shared/__tests__/worker-shutdown.test.ts +44 -39
  283. package/src/shared/approval-policy.ts +1 -1
  284. package/src/{activities/execute-cursor → shared}/attachment-resolver.ts +6 -6
  285. package/src/{activities/execute-cursor → shared}/blueprint-resolver.ts +7 -78
  286. package/src/shared/channel-attachment.ts +1 -1
  287. package/src/{activities/execute-cursor → shared}/cost-guard.ts +5 -1
  288. package/src/{activities/execute-cursor → shared}/env-resolver.ts +1 -1
  289. package/src/{activities/execute-cursor → shared}/exact-apply.ts +7 -7
  290. package/src/shared/execution-context.ts +45 -0
  291. package/src/{activities/execute-cursor → shared}/extract-structured-output.ts +10 -7
  292. package/src/shared/filereview/capture.ts +1 -1
  293. package/src/shared/heartbeat.ts +13 -33
  294. package/src/{activities/execute-cursor → shared}/persist-decision.ts +5 -2
  295. package/src/{activities/execute-cursor → shared}/skill-resolver.ts +20 -6
  296. package/src/shared/subagent-rows.ts +39 -0
  297. package/src/shared/worker-shutdown.ts +55 -25
  298. package/src/{activities/execute-cursor/__tests__/workspace-provision.test.ts → shared/workspace/__tests__/session-provision.test.ts} +25 -28
  299. package/src/shared/workspace/platform-dir.ts +1 -1
  300. package/src/{activities/execute-cursor/workspace-provision.ts → shared/workspace/session-provision.ts} +29 -16
  301. package/dist/activities/execute-cursor/attachment-resolver.js.map +0 -1
  302. package/dist/activities/execute-cursor/blueprint-resolver.js.map +0 -1
  303. package/dist/activities/execute-cursor/cost-guard.js.map +0 -1
  304. package/dist/activities/execute-cursor/env-resolver.js.map +0 -1
  305. package/dist/activities/execute-cursor/exact-apply.js.map +0 -1
  306. package/dist/activities/execute-cursor/extract-structured-output.js.map +0 -1
  307. package/dist/activities/execute-cursor/index.d.ts +0 -209
  308. package/dist/activities/execute-cursor/index.js +0 -2345
  309. package/dist/activities/execute-cursor/index.js.map +0 -1
  310. package/dist/activities/execute-cursor/persist-decision.js.map +0 -1
  311. package/dist/activities/execute-cursor/skill-resolver.js.map +0 -1
  312. package/dist/activities/execute-cursor/usage-accumulator.d.ts +0 -89
  313. package/dist/activities/execute-cursor/usage-accumulator.js +0 -121
  314. package/dist/activities/execute-cursor/usage-accumulator.js.map +0 -1
  315. package/dist/activities/execute-cursor/workspace-provision.d.ts +0 -42
  316. package/dist/activities/execute-cursor/workspace-provision.js.map +0 -1
  317. package/src/activities/execute-cursor/__tests__/usage-accumulator.test.ts +0 -164
  318. package/src/activities/execute-cursor/index.ts +0 -2876
  319. package/src/activities/execute-cursor/usage-accumulator.ts +0 -169
  320. /package/dist/{activities/execute-cursor → shared}/env-resolver.js +0 -0
@@ -12,7 +12,7 @@
12
12
  * path is written into the workspace itself.
13
13
  *
14
14
  * This module replaces the duplicated `getPlatformDir` helpers in
15
- * execute-cursor/skill-resolver.ts and execute-cursor/attachment-resolver.ts.
15
+ * execute-cursor/skill-resolver.ts and shared/attachment-resolver.ts.
16
16
  */
17
17
  /**
18
18
  * Compute the WORKSPACE-scoped HITL gate directory — the home for the STABLE
@@ -12,7 +12,7 @@
12
12
  * path is written into the workspace itself.
13
13
  *
14
14
  * This module replaces the duplicated `getPlatformDir` helpers in
15
- * execute-cursor/skill-resolver.ts and execute-cursor/attachment-resolver.ts.
15
+ * execute-cursor/skill-resolver.ts and shared/attachment-resolver.ts.
16
16
  */
17
17
  import { join } from "node:path";
18
18
  import { mkdir } from "node:fs/promises";
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Local workspace provisioning for a harness turn.
3
+ *
4
+ * Harness-agnostic: the Cursor activity is today's only caller, the turn
5
+ * runtime takes it over in S2 M3, and S3 retires the native twin
6
+ * (execute-deep-agent/setup.ts `provisionWorkspace`). Agents run LOCAL
7
+ * (cloud is disabled — see execute-cursor/cursor-mode.ts), so the runner
8
+ * must clone git-repo workspace entries itself and mount local-path entries
9
+ * before the agent runs. Cloud agents previously cloned git repos
10
+ * server-side; that path is no longer used.
11
+ */
12
+ import type { Config } from "../../config.js";
13
+ import type { Session } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
14
+ import type { ProvisionResult, WorkspaceBackend } from "./types.js";
15
+ /**
16
+ * The two runner settings provisioning reads. A `Pick` over `Config` rather
17
+ * than a fresh options type so a caller holding the whole `Config` (the turn
18
+ * orchestrator, and the runtime that replaces it) passes it unchanged, while
19
+ * the signature states exactly what is consumed: the root every workspace
20
+ * resolves under, and the mode that decides whether git entries are cloned
21
+ * or expected in place. A test constructs the two fields and nothing else.
22
+ */
23
+ export type SessionProvisionConfig = Pick<Config, "workspaceRootDir" | "mode">;
24
+ /** What {@link provisionSessionWorkspace} hands back to the harness. */
25
+ export interface SessionWorkspaceProvision {
26
+ /** The directories the agent should operate in (never empty). */
27
+ readonly workspaceDirs: string[];
28
+ /**
29
+ * Per-entry provision outcomes — carries the git metadata (repo URL, base
30
+ * branch, credential state) the write-back coordinator needs. Empty for a
31
+ * session with no workspace entries.
32
+ */
33
+ readonly provisionResults: ProvisionResult[];
34
+ /**
35
+ * The backend the entries were provisioned through — the write-back
36
+ * coordinator executes its git commands through it.
37
+ */
38
+ readonly workspaceBackend: WorkspaceBackend;
39
+ }
40
+ /**
41
+ * Provision the session's workspace entries for a LOCAL agent.
42
+ *
43
+ * Clones git-repo entries (using the user's GITHUB_TOKEN from the resolved
44
+ * execution environment) and mounts local-path entries, then returns the
45
+ * directories the agent should operate in — along with the provision results
46
+ * and backend the git write-back coordinator needs. A session with no
47
+ * workspace entries gets its own empty per-session directory (see
48
+ * session-root.ts) — never the shared root, which would leak other sessions'
49
+ * files into it.
50
+ *
51
+ * provisionGit is idempotent (it reuses an existing clone), so this is safe
52
+ * to call on every execution, including multi-turn and HITL reinvocations.
53
+ */
54
+ export declare function provisionSessionWorkspace(config: SessionProvisionConfig, session: Session, envVars: Record<string, string>, sessionId: string): Promise<SessionWorkspaceProvision>;
@@ -1,17 +1,20 @@
1
1
  /**
2
- * Local workspace provisioning for the Cursor harness.
2
+ * Local workspace provisioning for a harness turn.
3
3
  *
4
- * Cursor agents run LOCAL (cloud is disabled see cursor-mode.ts), so the
5
- * runner must clone git-repo workspace entries itself and mount local-path
6
- * entries before the agent runs, mirroring the native harness. Cloud agents
7
- * previously cloned git repos server-side; that path is no longer used.
4
+ * Harness-agnostic: the Cursor activity is today's only caller, the turn
5
+ * runtime takes it over in S2 M3, and S3 retires the native twin
6
+ * (execute-deep-agent/setup.ts `provisionWorkspace`). Agents run LOCAL
7
+ * (cloud is disabled see execute-cursor/cursor-mode.ts), so the runner
8
+ * must clone git-repo workspace entries itself and mount local-path entries
9
+ * before the agent runs. Cloud agents previously cloned git repos
10
+ * server-side; that path is no longer used.
8
11
  */
9
- import { WorkspaceProvisioner } from "../../shared/workspace/provisioner.js";
10
- import { LocalWorkspaceBackend } from "../../shared/workspace/local-backend.js";
11
- import { ensurePlatformDir } from "../../shared/workspace/platform-dir.js";
12
- import { resolveSessionWorkspaceRoot } from "../../shared/workspace/session-root.js";
12
+ import { WorkspaceProvisioner } from "./provisioner.js";
13
+ import { LocalWorkspaceBackend } from "./local-backend.js";
14
+ import { ensurePlatformDir } from "./platform-dir.js";
15
+ import { resolveSessionWorkspaceRoot } from "./session-root.js";
13
16
  /**
14
- * Provision the session's workspace entries for a LOCAL Cursor agent.
17
+ * Provision the session's workspace entries for a LOCAL agent.
15
18
  *
16
19
  * Clones git-repo entries (using the user's GITHUB_TOKEN from the resolved
17
20
  * execution environment) and mounts local-path entries, then returns the
@@ -24,7 +27,7 @@ import { resolveSessionWorkspaceRoot } from "../../shared/workspace/session-root
24
27
  * provisionGit is idempotent (it reuses an existing clone), so this is safe
25
28
  * to call on every execution, including multi-turn and HITL reinvocations.
26
29
  */
27
- export async function provisionCursorWorkspace(config, session, envVars, sessionId) {
30
+ export async function provisionSessionWorkspace(config, session, envVars, sessionId) {
28
31
  const entries = session.spec?.workspaceEntries ?? [];
29
32
  const platformDir = await ensurePlatformDir(sessionId);
30
33
  if (entries.length === 0) {
@@ -47,4 +50,4 @@ export async function provisionCursorWorkspace(config, session, envVars, session
47
50
  workspaceBackend: backend,
48
51
  };
49
52
  }
50
- //# sourceMappingURL=workspace-provision.js.map
53
+ //# sourceMappingURL=session-provision.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-provision.js","sourceRoot":"","sources":["../../../src/shared/workspace/session-provision.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AA6BhE;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAA8B,EAC9B,OAAgB,EAChB,OAA+B,EAC/B,SAAiB;IAEjB,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,gBAAgB,IAAI,EAAE,CAAC;IACrD,MAAM,WAAW,GAAG,MAAM,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAEvD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,WAAW,GAAG,MAAM,2BAA2B,CACnD,MAAM,CAAC,gBAAgB,EAAE,OAAO,EAAE,SAAS,CAC5C,CAAC;QACF,OAAO;YACL,aAAa,EAAE,CAAC,WAAW,CAAC;YAC5B,gBAAgB,EAAE,EAAE;YACpB,gBAAgB,EAAE,IAAI,qBAAqB,CAAC,WAAW,EAAE,WAAW,CAAC;SACtE,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC,MAAM,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC;IAEhF,MAAM,WAAW,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC/C,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,YAAY,CAC5C,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,EACpE,OAAO,EACP,OAAO,EACP,MAAM,CAAC,IAAI,KAAK,OAAO,EACvB,MAAM,CAAC,IAAI,KAAK,OAAO,CACxB,CAAC;IAEF,MAAM,IAAI,GAAG,OAAO;SACjB,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;SAC/B,MAAM,CAAC,CAAC,GAAG,EAAiB,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAEhD,OAAO;QACL,aAAa,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC;QACjE,gBAAgB,EAAE,OAAO;QACzB,gBAAgB,EAAE,OAAO;KAC1B,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stigmer/runner",
3
- "version": "3.14.1",
3
+ "version": "3.15.0",
4
4
  "description": "Embeddable Temporal worker for the Stigmer AI agent platform — handles agent execution, workflow orchestration, and MCP server management",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -104,9 +104,9 @@
104
104
  "@opentelemetry/sdk-metrics": "^2.0.0",
105
105
  "@opentelemetry/sdk-trace-base": "^2.0.0",
106
106
  "@opentelemetry/sdk-trace-node": "^2.0.0",
107
- "@stigmer/protos": "3.14.1",
108
- "@stigmer/temporal-codecs": "3.14.1",
109
- "@stigmer/zip-structure": "3.14.1",
107
+ "@stigmer/protos": "3.15.0",
108
+ "@stigmer/temporal-codecs": "3.15.0",
109
+ "@stigmer/zip-structure": "3.15.0",
110
110
  "@temporalio/activity": "1.16.2",
111
111
  "@temporalio/common": "1.16.2",
112
112
  "@temporalio/interceptors-opentelemetry": "1.16.2",
@@ -13,7 +13,16 @@
13
13
  * so a rejection here is attributable to the kit's assertion and not to some
14
14
  * other defect of the double. Where an invariant races a hang against the
15
15
  * interrupt bound, the bound is shortened through the assertion's parameter;
16
- * the production bound stays what `contract.ts` declares.
16
+ * the production bound stays what `contract.ts` declares. Every subject is
17
+ * booted first, as the kit's `describeHarnessContract` boots the adapters it
18
+ * runs (the assertion functions require it).
19
+ *
20
+ * The second half checks the kit's own driver — the runtime stand-in — for
21
+ * the facts a real adapter depends on and the fake never notices: the record
22
+ * carries the persisted status (an adapter may read its grants from
23
+ * `execution.status`, as the runtime guarantees), the engine's view carries
24
+ * the driver's ids and decisions, and a stop lands only once the engine
25
+ * reports it is parked.
17
26
  */
18
27
 
19
28
  import { describe, it, expect } from "vitest";
@@ -22,6 +31,7 @@ import { ApprovalAction, ToolCallStatus } from "@stigmer/protos/ai/stigmer/agent
22
31
 
23
32
  import type { HarnessAdapter, TurnInput, TurnOutcome, TurnSink } from "../../harness/types.js";
24
33
  import {
34
+ ExecutionDriver,
25
35
  assertConcurrentTurnsAreIndependent,
26
36
  assertDecisionsExecuteExactlyOnce,
27
37
  assertEveryExitIsAnOutcome,
@@ -33,13 +43,21 @@ import {
33
43
  } from "../harness-contract/contract.js";
34
44
  import { scriptedSubject } from "../harness-contract/scripted-adapter.js";
35
45
  import type { ScriptedSubject } from "../harness-contract/scripted-adapter.js";
36
- import type { HarnessContractSubject, TurnScenario } from "../harness-contract/types.js";
46
+ import { scenario } from "../harness-contract/types.js";
47
+ import type { EngineView, HarnessContractSubject, TurnScenario } from "../harness-contract/types.js";
48
+ import { findToolCallRow } from "../proto-helpers.js";
37
49
 
38
50
  /** Short enough to keep this file fast; long enough that an honest microtask settle never trips it. */
39
51
  const SHORT_BOUND_MS = 100;
40
52
 
41
53
  // ── Wrapping helpers ────────────────────────────────────────────────────────
42
54
 
55
+ /** The kit boots before it asserts; so does every arm here. */
56
+ async function booted<S extends HarnessContractSubject>(subject: S): Promise<S> {
57
+ await subject.adapter.boot(subject.config);
58
+ return subject;
59
+ }
60
+
43
61
  /** The honest fake's adapter with the named members replaced. */
44
62
  function adapterOver(inner: HarnessAdapter, name: string, patch: Partial<HarnessAdapter>): HarnessAdapter {
45
63
  return {
@@ -58,9 +76,11 @@ function sinkOver(inner: TurnSink, patch: Partial<TurnSink>): TurnSink {
58
76
  return {
59
77
  status: inner.status,
60
78
  stopSignal: inner.stopSignal,
79
+ setupTiming: inner.setupTiming,
61
80
  requestPersist: () => inner.requestPersist(),
62
- recordActivity: () => inner.recordActivity(),
81
+ recordActivity: (detail) => inner.recordActivity(detail),
63
82
  reportUsage: (delta) => inner.reportUsage(delta),
83
+ reportProgress: (label) => inner.reportProgress(label),
64
84
  bindHarnessState: (id) => inner.bindHarnessState(id),
65
85
  ...patch,
66
86
  };
@@ -70,9 +90,11 @@ function sinkOver(inner: TurnSink, patch: Partial<TurnSink>): TurnSink {
70
90
  function subjectOver(inner: ScriptedSubject, adapter: HarnessAdapter): HarnessContractSubject {
71
91
  return {
72
92
  name: adapter.name,
93
+ harness: inner.harness,
73
94
  adapter,
74
95
  config: inner.config,
75
- arrange: (turn) => inner.arrange(turn),
96
+ arrange: (turn, view) => inner.arrange(turn, view),
97
+ whenHanging: () => inner.whenHanging(),
76
98
  executionCount: (toolCallId) => inner.executionCount(toolCallId),
77
99
  };
78
100
  }
@@ -106,9 +128,9 @@ function executesUndecidedProposals(): HarnessContractSubject {
106
128
  });
107
129
  return {
108
130
  ...subjectOver(inner, adapter),
109
- arrange: (turn: TurnScenario) => {
131
+ arrange: (turn: TurnScenario, view: EngineView) => {
110
132
  proposedIds = turn.flatMap((step) => (step.kind === "propose" ? [step.toolCallId] : []));
111
- inner.arrange(turn);
133
+ inner.arrange(turn, view);
112
134
  },
113
135
  };
114
136
  }
@@ -196,34 +218,108 @@ function serializesTurns(): HarnessContractSubject {
196
218
 
197
219
  describe("harness contract kit self-check — every invariant can fail", () => {
198
220
  it("invariant 1 fires when runTurn throws a CancelledFailure", async () => {
199
- await expect(assertEveryExitIsAnOutcome(throwsCancelledFailure(), SHORT_BOUND_MS)).rejects.toThrow(/broken:throws-CancelledFailure: runTurn rejected with a CancelledFailure/);
221
+ await expect(assertEveryExitIsAnOutcome(await booted(throwsCancelledFailure()), SHORT_BOUND_MS)).rejects.toThrow(/broken:throws-CancelledFailure: runTurn rejected with a CancelledFailure/);
200
222
  });
201
223
 
202
224
  it("invariant 2 fires when an undecided proposal executes", async () => {
203
- await expect(assertProposalIsWaitingAndUnexecuted(executesUndecidedProposals())).rejects.toThrow(/broken:executes-undecided: .*awaiting_approval/);
225
+ await expect(assertProposalIsWaitingAndUnexecuted(await booted(executesUndecidedProposals()))).rejects.toThrow(/broken:executes-undecided: .*awaiting_approval/);
204
226
  });
205
227
 
206
228
  it("invariant 3 fires when a settled row is re-gated on a later invocation", async () => {
207
- await expect(assertDecisionsExecuteExactlyOnce(reGatesSettledRows())).rejects.toThrow(/broken:re-gates-settled: .*must not re-gate/);
229
+ await expect(assertDecisionsExecuteExactlyOnce(await booted(reGatesSettledRows()))).rejects.toThrow(/broken:re-gates-settled: .*must not re-gate/);
208
230
  });
209
231
 
210
232
  it("invariant 4 fires when the adapter ignores stopSignal", async () => {
211
- await expect(assertStopSignalInterrupts(ignoresStopSignal(), SHORT_BOUND_MS)).rejects.toThrow(/broken:ignores-stopSignal: runTurn did not settle within 100ms/);
233
+ await expect(assertStopSignalInterrupts(await booted(ignoresStopSignal()), SHORT_BOUND_MS)).rejects.toThrow(/broken:ignores-stopSignal: runTurn did not settle within 100ms/);
212
234
  });
213
235
 
214
236
  it("invariant 5 fires when usage is reported as running totals", async () => {
215
- await expect(assertUsageReachesSinkAsDeltas(reportsCumulativeUsage())).rejects.toThrow(/broken:cumulative-usage: .*must sum to what the engine emitted/);
237
+ await expect(assertUsageReachesSinkAsDeltas(await booted(reportsCumulativeUsage()))).rejects.toThrow(/broken:cumulative-usage: .*must sum to what the engine emitted/);
216
238
  });
217
239
 
218
240
  it("invariant 6 fires when an adapter claims engine-minted and never binds", async () => {
219
- await expect(assertStateIdCapabilityAgrees(claimsEngineMintedNeverBinds())).rejects.toThrow(/broken:claims-engine-minted: .*must bind its state id/);
241
+ await expect(assertStateIdCapabilityAgrees(await booted(claimsEngineMintedNeverBinds()))).rejects.toThrow(/broken:claims-engine-minted: .*must bind its state id/);
220
242
  });
221
243
 
222
244
  it("invariant 7 fires when releaseSession rejects an unknown session", async () => {
223
- await expect(assertLifetimesResolve(refusesUnknownRelease())).rejects.toThrow(/broken:refuses-unknown-release: releaseSession for an unknown session rejected/);
245
+ await expect(assertLifetimesResolve(await booted(refusesUnknownRelease()))).rejects.toThrow(/broken:refuses-unknown-release: releaseSession for an unknown session rejected/);
224
246
  });
225
247
 
226
248
  it("invariant 8 fires when the adapter serializes turns through shared state", async () => {
227
- await expect(assertConcurrentTurnsAreIndependent(serializesTurns(), SHORT_BOUND_MS)).rejects.toThrow(/broken:serializes-turns: runTurn did not settle within 100ms/);
249
+ await expect(assertConcurrentTurnsAreIndependent(await booted(serializesTurns()), SHORT_BOUND_MS)).rejects.toThrow(/broken:serializes-turns: runTurn did not settle within 100ms/);
250
+ });
251
+ });
252
+
253
+ // ── The driver: the runtime stand-in's own guarantees ───────────────────────
254
+
255
+ const WRITE_BETA = { kind: "write", resource: "/work/beta.txt" } as const;
256
+
257
+ describe("harness contract kit self-check — the driver stands in for the runtime faithfully", () => {
258
+ it("hands the adapter the persisted status on the record AND the sink, as two clones", async () => {
259
+ const subject = await booted(honest());
260
+ const driver = new ExecutionDriver(subject, "driver-record");
261
+ const id = "driver-record-write";
262
+
263
+ const first = await driver.turn([scenario.propose(id, WRITE_BETA)]);
264
+ expect(first.outcome.kind).toBe("awaiting_approval");
265
+ expect(first.input.execution.status?.messages ?? [], "a first turn's record carries no persisted status").toHaveLength(0);
266
+ driver.decide(id, ApprovalAction.APPROVE);
267
+
268
+ const second = driver.begin([scenario.propose(id, WRITE_BETA)]);
269
+ const onRecord = second.input.execution.status;
270
+ expect(onRecord, "the reinvocation's record must carry what the previous turn persisted").toBeDefined();
271
+ expect(findToolCallRow(onRecord!, id)?.approvalAction, "the decision is on the record's row").toBe(ApprovalAction.APPROVE);
272
+ expect(findToolCallRow(second.sink.status, id)?.approvalAction, "and on the sink's row").toBe(ApprovalAction.APPROVE);
273
+ expect(onRecord, "the record's copy and the sink's copy are distinct objects, as after a real persist and read-back").not.toBe(second.sink.status);
274
+ expect(second.input.approvalDecisions.get(id), "the decisions map is the runtime's reader over the same rows").toBe(ApprovalAction.APPROVE);
275
+ await second.settled;
276
+ });
277
+
278
+ it("arranges the engine with the driver's ids and the decisions the prompt will carry", async () => {
279
+ const inner = await booted(honest());
280
+ const views: EngineView[] = [];
281
+ const subject: HarnessContractSubject = {
282
+ ...inner,
283
+ arrange: (turn, view) => {
284
+ views.push(view);
285
+ inner.arrange(turn, view);
286
+ },
287
+ };
288
+ const driver = new ExecutionDriver(subject, "driver-view");
289
+ const id = "driver-view-write";
290
+
291
+ await driver.turn([scenario.propose(id, WRITE_BETA)]);
292
+ driver.decide(id, ApprovalAction.SKIP);
293
+ await driver.turn([scenario.propose(id, WRITE_BETA), scenario.say("on")]);
294
+
295
+ expect(views.map((v) => v.executionId)).toEqual([driver.executionId, driver.executionId]);
296
+ expect(views.map((v) => v.sessionId)).toEqual([driver.sessionId, driver.sessionId]);
297
+ expect(views[0]!.approvalDecisions.size, "nothing decided before the first turn").toBe(0);
298
+ expect(views[1]!.approvalDecisions.get(id), "the reinvocation's view carries the decision").toBe(ApprovalAction.SKIP);
299
+ });
300
+
301
+ it("stops a turn only once the engine reports it is parked, never during setup", async () => {
302
+ const inner = await booted(honest());
303
+ let sinkInFlight: TurnSink | undefined;
304
+ let abortedWhenParked: boolean | undefined;
305
+ // Observes the signal at the instant the engine reports the hang; the
306
+ // driver's own abort is chained after this observer.
307
+ const subject: HarnessContractSubject = {
308
+ ...inner,
309
+ whenHanging: () =>
310
+ inner.whenHanging().then(() => {
311
+ abortedWhenParked = sinkInFlight?.stopSignal.aborted;
312
+ }),
313
+ };
314
+ const driver = new ExecutionDriver(subject, "driver-stop");
315
+
316
+ const turn = driver.begin([scenario.say("setting up"), scenario.hang(), scenario.say("never")], { stopWhenHanging: "kit: stop" });
317
+ sinkInFlight = turn.sink;
318
+ const outcome = await turn.settled;
319
+
320
+ expect(outcome.kind).toBe("interrupted");
321
+ expect(abortedWhenParked, "at the moment the engine reported the hang the signal was still live").toBe(false);
322
+ expect(turn.sink.stopSignal.aborted, "and it was aborted after").toBe(true);
323
+ expect(turn.sink.status.messages.map((m) => m.content), "the stop landed in the hang, after the setup step and before the step after it").toEqual(["setting up"]);
228
324
  });
229
325
  });
@@ -0,0 +1,104 @@
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
+
15
+ import { create } from "@bufbuild/protobuf";
16
+ import { AgentExecutionSchema, type AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
17
+ import { AgentExecutionSpecSchema, ExecutionConfigSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/spec_pb";
18
+ import { SessionSchema, type Session } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
19
+ import { SessionSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/session/v1/spec_pb";
20
+ import type { WorkspaceEntry } from "@stigmer/protos/ai/stigmer/agentic/session/v1/workspace_pb";
21
+ import { AgentSchema, type Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
22
+ import { AgentSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
23
+ import { AgentInstanceSchema, type AgentInstance } from "@stigmer/protos/ai/stigmer/agentic/agentinstance/v1/api_pb";
24
+ import { AgentInstanceSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/agentinstance/v1/spec_pb";
25
+ import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
26
+
27
+ import { ExecutionRecord, type ExecutionRecordInput } from "./hermetic-activity.js";
28
+ import { FIXTURE_MODEL } from "./model-registry-fixture.js";
29
+
30
+ /** The ids a record's four resources carry. */
31
+ export interface ExecutionRecordIds {
32
+ readonly org: string;
33
+ readonly executionId: string;
34
+ readonly sessionId: string;
35
+ readonly agentInstanceId: string;
36
+ readonly agentId: string;
37
+ readonly agentName: string;
38
+ }
39
+
40
+ export const DEFAULT_RECORD_IDS: ExecutionRecordIds = {
41
+ org: "hermetic-org",
42
+ executionId: "aex_hermetic_0001",
43
+ sessionId: "ses_hermetic_0001",
44
+ agentInstanceId: "ain_hermetic_0001",
45
+ agentId: "agt_hermetic_0001",
46
+ agentName: "hermetic-agent",
47
+ };
48
+
49
+ export interface ExecutionRecordOptions {
50
+ /** The user's message for this execution. */
51
+ readonly message: string;
52
+ /** The agent's instructions (system prompt body). */
53
+ readonly instructions?: string;
54
+ /** Session workspace entries (a `local_path` entry turns on capture mode). */
55
+ readonly workspaceEntries?: WorkspaceEntry[];
56
+ /** The requested model; the pinned fixture model when omitted. */
57
+ readonly modelName?: string;
58
+ readonly autoApproveAll?: boolean;
59
+ /**
60
+ * `ExecutionConfig.max_cost_usd`: the per-message cost budget the runtime
61
+ * enforces as a hard stop (cost-guard.ts). Omitted or 0 = no cap, the
62
+ * proto's default. Priced against the registry fixture's round numbers, so
63
+ * a scenario can state its overrun exactly (600 000 input tokens = $0.60).
64
+ */
65
+ readonly maxCostUsd?: number;
66
+ /** The control plane's STOP lever; see `ExecutionRecordInput.controlSignal`. */
67
+ readonly controlSignal?: ExecutionRecordInput["controlSignal"];
68
+ readonly ids?: ExecutionRecordIds;
69
+ }
70
+
71
+ export function executionRecordFixture(options: ExecutionRecordOptions): ExecutionRecord {
72
+ const ids = options.ids ?? DEFAULT_RECORD_IDS;
73
+ const execution: AgentExecution = create(AgentExecutionSchema, {
74
+ metadata: create(ApiResourceMetadataSchema, { id: ids.executionId, org: ids.org, name: ids.executionId }),
75
+ spec: create(AgentExecutionSpecSchema, {
76
+ sessionId: ids.sessionId,
77
+ message: options.message,
78
+ autoApproveAll: options.autoApproveAll ?? false,
79
+ executionConfig: create(ExecutionConfigSchema, {
80
+ modelName: options.modelName ?? FIXTURE_MODEL,
81
+ maxCostUsd: options.maxCostUsd ?? 0,
82
+ }),
83
+ }),
84
+ });
85
+ const session: Session = create(SessionSchema, {
86
+ metadata: create(ApiResourceMetadataSchema, { id: ids.sessionId, org: ids.org, name: ids.sessionId }),
87
+ spec: create(SessionSpecSchema, {
88
+ agentInstanceId: ids.agentInstanceId,
89
+ workspaceEntries: options.workspaceEntries ?? [],
90
+ }),
91
+ });
92
+ const agentInstance: AgentInstance = create(AgentInstanceSchema, {
93
+ metadata: create(ApiResourceMetadataSchema, { id: ids.agentInstanceId, org: ids.org, name: ids.agentInstanceId }),
94
+ spec: create(AgentInstanceSpecSchema, { agentId: ids.agentId }),
95
+ });
96
+ const agent: Agent = create(AgentSchema, {
97
+ metadata: create(ApiResourceMetadataSchema, { id: ids.agentId, org: ids.org, name: ids.agentName }),
98
+ spec: create(AgentSpecSchema, {
99
+ description: "Hermetic fixture agent",
100
+ instructions: options.instructions ?? "You are the hermetic fixture agent. Answer briefly.",
101
+ }),
102
+ });
103
+ return new ExecutionRecord({ execution, session, agentInstance, agent, controlSignal: options.controlSignal });
104
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The child entry `__tests__/harness-boot-order.test.ts` spawns: one FRESH
3
+ * Node process that does exactly what the composition roots do before
4
+ * bootstrap — import `harness-adapters.js` and `harness/registry.js`, then
5
+ * `bootHarnesses` on a proxy-mode config — and reports how it went.
6
+ *
7
+ * Why a child process: the `node:http2` ESM facade is snapshotted once per
8
+ * process at its first import, so the positive load-order contract ("the
9
+ * patch reached the facade") cannot be observed inside a shared vitest
10
+ * worker that has already imported half the runner. A fresh process is the
11
+ * only honest instrument (`http2-interceptor.test.ts` says as much).
12
+ *
13
+ * Arms (argv[2]):
14
+ * - `boot`: import the two pre-boot modules, boot with a proxy endpoint and
15
+ * a bound token ref. Success means the pre-boot graph was connect-free,
16
+ * both interceptors installed, `assertHttp2ConnectPatched` passed, and the
17
+ * SDK slice loaded from inside `boot`.
18
+ * - `boot-after-connect-node`: the same, after importing the Stigmer client
19
+ * (connect-node) FIRST. Must fail with the facade sentence: proves the
20
+ * guard is live inside `boot`, so a future regression is loud.
21
+ *
22
+ * Output: one line, `harness-boot-order: ok` or `harness-boot-order: <message>`,
23
+ * then exit 0 on success and 1 on a rejection. The proxy endpoint is an inert
24
+ * loopback nothing listens on; boot dials nothing.
25
+ */
26
+
27
+ import { testConfig } from "./config-fixture.js";
28
+
29
+ const arm = process.argv[2];
30
+
31
+ async function main(): Promise<void> {
32
+ if (arm === "boot-after-connect-node") {
33
+ await import("../client/stigmer-client.js");
34
+ } else if (arm !== "boot") {
35
+ throw new Error(`harness-boot-order-child: unknown arm '${String(arm)}' (expected 'boot' or 'boot-after-connect-node')`);
36
+ }
37
+
38
+ const [{ HARNESS_ADAPTERS }, { adaptersOf, bootHarnesses }] = await Promise.all([
39
+ import("../harness-adapters.js"),
40
+ import("../harness/registry.js"),
41
+ ]);
42
+ const config = testConfig({
43
+ proxyEndpoint: "http://127.0.0.1:1",
44
+ proxyTokenRef: { current: "boot-order-test-token" },
45
+ });
46
+ await bootHarnesses(adaptersOf(HARNESS_ADAPTERS), config);
47
+ }
48
+
49
+ main().then(
50
+ () => {
51
+ process.stdout.write("harness-boot-order: ok\n");
52
+ process.exit(0);
53
+ },
54
+ (err: unknown) => {
55
+ process.stdout.write(`harness-boot-order: ${err instanceof Error ? err.message : String(err)}\n`);
56
+ process.exit(1);
57
+ },
58
+ );