@stigmer/runner 3.14.1 → 3.15.1

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
@@ -21,17 +21,24 @@
21
21
  * (await import("../../../../__test-utils__/hermetic-activity.js")).hermeticStigmerClientModule());
22
22
  * ```
23
23
  *
24
- * Network: the activity's only HTTP fetch is the model registry
25
- * (`model-pricing-data.ts`, `shared/model-registry.ts`; both fail SOFT to
26
- * defaults with a 60s failure cache, which would make the goldens depend on
27
- * DEFAULT_PRICING and log warnings on every run). `fetch` is stubbed to answer
28
- * one registry document — and to THROW for any other URL, so a new network
29
- * dependency on the activity path fails the hermetic run instead of leaking.
24
+ * Network: the registry document and the `fetch` stub that serves it are
25
+ * the runtime's fixtures (`src/__test-utils__/model-registry-fixture.ts`);
26
+ * the record's four resources come from `execution-record-fixture.ts` with
27
+ * this harness's ids and model laid over the defaults.
30
28
  *
31
29
  * The fixture model is `composer-2.5`, pinned (not Auto) on purpose: Auto short-
32
30
  * circuits `resolveServiceTierParams` before the catalog, and a pinned model runs
33
31
  * the catalog path, the variant-param pinning, and the `run.wait()` model echo
34
32
  * check — more of the production path under the golden.
33
+ *
34
+ * Where a scenario reaches the knobs that drive the terminal table, each on
35
+ * the object that models the thing deciding it: the execution's cost budget
36
+ * and the control plane's STOP answer on the record (`CursorRecordOptions`);
37
+ * a control-plane fault on the client (`clientOverrides`); the runner's stall
38
+ * and lock windows on the scenario's `Config` (`config`); an SDK failure on
39
+ * the SDK double (`ScriptedSdkOptions`); an SDK-side cancel or a mid-stream
40
+ * wedge as an `effect` step on the run. Nothing here is a switch in production
41
+ * code — every knob is a value the production path already reads.
35
42
  */
36
43
 
37
44
  import { execFileSync } from "node:child_process";
@@ -39,31 +46,13 @@ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
39
46
  import { dirname, join } from "node:path";
40
47
  import { create } from "@bufbuild/protobuf";
41
48
  import type { ModelListItem } from "@cursor/sdk";
42
- import { vi } from "vitest";
43
- import {
44
- AgentExecutionSchema,
45
- type AgentExecution,
46
- } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
47
- import {
48
- AgentExecutionSpecSchema,
49
- ExecutionConfigSchema,
50
- } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/spec_pb";
51
- import { SessionSchema, type Session } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
52
- import { SessionSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/session/v1/spec_pb";
53
49
  import {
54
50
  LocalPathSourceSchema,
55
51
  WorkspaceEntrySchema,
56
52
  WorkspaceSourceSchema,
57
53
  type WorkspaceEntry,
58
54
  } from "@stigmer/protos/ai/stigmer/agentic/session/v1/workspace_pb";
59
- import { AgentSchema, type Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
60
- import { AgentSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
61
- import {
62
- AgentInstanceSchema,
63
- type AgentInstance,
64
- } from "@stigmer/protos/ai/stigmer/agentic/agentinstance/v1/api_pb";
65
- import { AgentInstanceSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/agentinstance/v1/spec_pb";
66
- import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
55
+ import type { StigmerClient } from "../../../client/stigmer-client.js";
67
56
  import type { Config } from "../../../config.js";
68
57
  import type { ExecuteActivityInput } from "../../../shared/activity-input.js";
69
58
  import {
@@ -75,6 +64,8 @@ import {
75
64
  type HermeticEnvironment,
76
65
  type InvocationControls,
77
66
  } from "../../../__test-utils__/hermetic-activity.js";
67
+ import { executionRecordFixture, type ExecutionRecordOptions } from "../../../__test-utils__/execution-record-fixture.js";
68
+ import { FIXTURE_MODEL } from "../../../__test-utils__/model-registry-fixture.js";
78
69
  import { _resetAgentSessionCacheForTests } from "../agent-session-cache.js";
79
70
  import { _resetPricingCache } from "../model-pricing-data.js";
80
71
  import { resetCatalogCacheForTests } from "../service-tier.js";
@@ -92,8 +83,8 @@ export const FIXTURE = {
92
83
  agentInstanceId: "ain_hermetic_0001",
93
84
  agentId: "agt_hermetic_0001",
94
85
  agentName: "hermetic-agent",
95
- /** The pinned model; in the registry stub AND the SDK catalog below. */
96
- model: "composer-2.5",
86
+ /** The pinned model; in the registry fixture AND the SDK catalog below. */
87
+ model: FIXTURE_MODEL,
97
88
  cursorApiKey: "hermetic-cursor-api-key",
98
89
  } as const;
99
90
 
@@ -101,105 +92,29 @@ export const FIXTURE = {
101
92
  // The record
102
93
  // ---------------------------------------------------------------------------
103
94
 
104
- export interface CursorRecordOptions {
105
- /** The user's message for this execution. */
106
- readonly message: string;
107
- /** The agent's instructions (system prompt body). */
108
- readonly instructions?: string;
109
- /** Session workspace entries (a `local_path` entry turns on capture mode). */
110
- readonly workspaceEntries?: WorkspaceEntry[];
111
- readonly modelName?: string;
112
- readonly autoApproveAll?: boolean;
113
- }
95
+ /** The record's knobs; the ids and the default model are this harness's fixture. */
96
+ export type CursorRecordOptions = Omit<ExecutionRecordOptions, "ids">;
114
97
 
115
- /** The four resources of one execution, wired by id into a chain. */
98
+ /** The four resources of one execution, wired by id into a chain, under the Cursor fixture ids. */
116
99
  export function cursorExecutionRecord(options: CursorRecordOptions): ExecutionRecord {
117
- const execution: AgentExecution = create(AgentExecutionSchema, {
118
- metadata: create(ApiResourceMetadataSchema, {
119
- id: FIXTURE.executionId,
100
+ return executionRecordFixture({
101
+ ...options,
102
+ modelName: options.modelName ?? FIXTURE.model,
103
+ ids: {
120
104
  org: FIXTURE.org,
121
- name: FIXTURE.executionId,
122
- }),
123
- spec: create(AgentExecutionSpecSchema, {
105
+ executionId: FIXTURE.executionId,
124
106
  sessionId: FIXTURE.sessionId,
125
- message: options.message,
126
- autoApproveAll: options.autoApproveAll ?? false,
127
- executionConfig: create(ExecutionConfigSchema, {
128
- modelName: options.modelName ?? FIXTURE.model,
129
- }),
130
- }),
131
- });
132
- const session: Session = create(SessionSchema, {
133
- metadata: create(ApiResourceMetadataSchema, {
134
- id: FIXTURE.sessionId,
135
- org: FIXTURE.org,
136
- name: FIXTURE.sessionId,
137
- }),
138
- spec: create(SessionSpecSchema, {
139
107
  agentInstanceId: FIXTURE.agentInstanceId,
140
- workspaceEntries: options.workspaceEntries ?? [],
141
- }),
142
- });
143
- const agentInstance: AgentInstance = create(AgentInstanceSchema, {
144
- metadata: create(ApiResourceMetadataSchema, {
145
- id: FIXTURE.agentInstanceId,
146
- org: FIXTURE.org,
147
- name: FIXTURE.agentInstanceId,
148
- }),
149
- spec: create(AgentInstanceSpecSchema, { agentId: FIXTURE.agentId }),
150
- });
151
- const agent: Agent = create(AgentSchema, {
152
- metadata: create(ApiResourceMetadataSchema, {
153
- id: FIXTURE.agentId,
154
- org: FIXTURE.org,
155
- name: FIXTURE.agentName,
156
- }),
157
- spec: create(AgentSpecSchema, {
158
- description: "Hermetic fixture agent",
159
- instructions: options.instructions ?? "You are the hermetic fixture agent. Answer briefly.",
160
- }),
108
+ agentId: FIXTURE.agentId,
109
+ agentName: FIXTURE.agentName,
110
+ },
161
111
  });
162
- return new ExecutionRecord({ execution, session, agentInstance, agent });
163
112
  }
164
113
 
165
114
  // ---------------------------------------------------------------------------
166
- // The registry document and the SDK catalog
115
+ // The SDK catalog
167
116
  // ---------------------------------------------------------------------------
168
117
 
169
- /**
170
- * The model registry document both readers parse (`parsePricingTable` wants
171
- * `harness: "cursor"` + `pricing`; `parseRegistry` wants `id` + `provider` and
172
- * reads `capabilities.vision`). One entry, the fixture model, priced at round
173
- * numbers so the golden's `estimatedCostUsd` is legible.
174
- */
175
- export const REGISTRY_DOCUMENT = {
176
- models: [
177
- {
178
- id: FIXTURE.model,
179
- displayName: "Composer 2.5 (hermetic fixture)",
180
- provider: "cursor",
181
- harness: "cursor",
182
- costTier: "standard",
183
- featured: true,
184
- capabilities: { vision: true },
185
- pricing: {
186
- inputPricePerMillion: 1.0,
187
- outputPricePerMillion: 4.0,
188
- cacheWritePricePerMillion: 1.0,
189
- cacheReadPricePerMillion: 0.1,
190
- },
191
- pricingVariants: {
192
- fast: {
193
- inputPricePerMillion: 3.0,
194
- outputPricePerMillion: 12.0,
195
- cacheWritePricePerMillion: 3.0,
196
- cacheReadPricePerMillion: 0.3,
197
- },
198
- },
199
- },
200
- ],
201
- } as const;
202
-
203
118
  /** The SDK catalog entry for the fixture model: both pinnable params declared. */
204
119
  export const SDK_CATALOG: readonly ModelListItem[] = [
205
120
  {
@@ -212,26 +127,6 @@ export const SDK_CATALOG: readonly ModelListItem[] = [
212
127
  },
213
128
  ];
214
129
 
215
- /**
216
- * Stub `fetch` to answer the registry document and refuse everything else.
217
- * Returns the URLs fetched, for the "no other network" assertion.
218
- */
219
- export function stubRegistryFetch(): { readonly urls: string[]; restore(): void } {
220
- const urls: string[] = [];
221
- vi.stubGlobal(
222
- "fetch",
223
- vi.fn(async (input: string | URL | Request) => {
224
- const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
225
- urls.push(url);
226
- if (!url.includes("/model-registry")) {
227
- throw new Error(`hermetic run attempted a non-registry network call: ${url}`);
228
- }
229
- return { ok: true, status: 200, json: async () => REGISTRY_DOCUMENT } as unknown as Response;
230
- }),
231
- );
232
- return { urls, restore: () => vi.unstubAllGlobals() };
233
- }
234
-
235
130
  // ---------------------------------------------------------------------------
236
131
  // Config
237
132
  // ---------------------------------------------------------------------------
@@ -369,6 +264,8 @@ export interface CursorScenario {
369
264
  readonly clock: ScriptedClock;
370
265
  readonly record: ExecutionRecord;
371
266
  readonly sdk: ScriptedCursorSdk;
267
+ /** The runner this scenario runs on: the OSS posture plus the scenario's knobs. */
268
+ readonly config: Config;
372
269
  }
373
270
 
374
271
  export interface CursorScenarioOptions {
@@ -376,6 +273,19 @@ export interface CursorScenarioOptions {
376
273
  readonly clock: ScriptedClock;
377
274
  readonly record: ExecutionRecord;
378
275
  readonly sdk: ScriptedSdkOptions;
276
+ /**
277
+ * Control-plane facets the scenario opts INTO, or faults it injects, over
278
+ * the record's everyday answers (`ExecutionRecord.client`): a rejecting
279
+ * `getAgent` is how a blueprint-resolution failure is staged.
280
+ */
281
+ readonly clientOverrides?: Partial<StigmerClient>;
282
+ /**
283
+ * Runner knobs over {@link hermeticCursorConfig}: a scenario that needs the
284
+ * stall watchdog or the workspace-lock wait to expire states the window
285
+ * here. A property of the runner the scenario runs on, not of one turn, so
286
+ * it lives on the scenario and every turn of it sees the same `Config`.
287
+ */
288
+ readonly config?: Partial<Config>;
379
289
  }
380
290
 
381
291
  /** Bind the record and the SDK for a scenario; resets the harness caches first. */
@@ -383,8 +293,14 @@ export function beginCursorScenario(options: CursorScenarioOptions): CursorScena
383
293
  resetCursorModuleState();
384
294
  const sdk = new ScriptedCursorSdk(options.sdk);
385
295
  bindScriptedSdk(sdk);
386
- bindHermeticClient(options.record.client());
387
- return { env: options.env, clock: options.clock, record: options.record, sdk };
296
+ bindHermeticClient(options.record.client(options.clientOverrides));
297
+ return {
298
+ env: options.env,
299
+ clock: options.clock,
300
+ record: options.record,
301
+ sdk,
302
+ config: { ...hermeticCursorConfig(options.env), ...options.config },
303
+ };
388
304
  }
389
305
 
390
306
  export interface CursorTurnOptions {
@@ -396,26 +312,30 @@ export interface CursorTurnOptions {
396
312
  }
397
313
 
398
314
  /**
399
- * Run ONE `ExecuteCursor` invocation for the scenario. The activities are
400
- * constructed per invocation (the factory constructs its client, which is the
401
- * one bound at `beginCursorScenario`).
315
+ * Run ONE `ExecuteCursor` invocation for the scenario: the real Cursor
316
+ * adapter under the real turn runtime, as the composition roots wire them.
317
+ * Built per invocation (the registry constructs its client, which is the one
318
+ * bound at `beginCursorScenario`; the adapter boots on the scenario's config).
402
319
  */
403
320
  export async function runCursorTurn(
404
321
  scenario: CursorScenario,
405
322
  options: CursorTurnOptions = {},
406
323
  ): Promise<ActivityInvocation> {
407
324
  // Imported lazily so the scenario file's `vi.mock` declarations are in
408
- // force before the activity module (and, through it, `@cursor/sdk` and the
409
- // client) is loaded.
410
- const { createCursorActivities } = await import("../index.js");
411
- const activities = createCursorActivities(hermeticCursorConfig(scenario.env));
325
+ // force before the adapter module is loaded and before its `boot` loads
326
+ // `@cursor/sdk` (through `turn.ts`) and the registry loads the client.
327
+ const { createCursorAdapter } = await import("../adapter.js");
328
+ const { createHarnessActivities } = await import("../../../harness/registry.js");
329
+ const adapter = createCursorAdapter();
330
+ await adapter.boot(scenario.config);
331
+ const activities = await createHarnessActivities([{ harness: "cursor", adapter }], scenario.config);
412
332
  // The typed wire shape the control plane's workflow sends (activity-input.ts).
413
333
  const input: ExecuteActivityInput = {
414
334
  execution_id: scenario.record.executionId,
415
335
  thread_id: options.threadId ?? "",
416
336
  turn_seq: options.turnSeq ?? 0,
417
337
  };
418
- return runActivityHermetically(activities.ExecuteCursor, [input], {
338
+ return runActivityHermetically(activities.ExecuteCursor!, [input], {
419
339
  taskQueue: "hermetic-test-queue",
420
340
  onControls: options.onControls,
421
341
  });
@@ -42,7 +42,11 @@
42
42
  *
43
43
  * Every `send()` consumes the NEXT script in the agent's queue: turn 1, then
44
44
  * the resumed turn 2 on the same parked agent. A `send()` with no script left
45
- * is a test bug and throws.
45
+ * is a test bug and throws. A golden scenario declares every script up front
46
+ * (`turns`); a driver that learns what the next turn plays only just before
47
+ * it runs — the harness contract kit's Cursor subject — arranges it with
48
+ * {@link ScriptedCursorAgent.arrangeNextTurn}, which REPLACES the slot the
49
+ * next `send()` will consume.
46
50
  */
47
51
 
48
52
  import type {
@@ -284,6 +288,11 @@ export interface RecordedSend {
284
288
  readonly hasOnDelta: boolean;
285
289
  }
286
290
 
291
+ /** The run id a send is given when the scenario named none: `run-<agentId>-<n>`, `n` counting sends from 1. */
292
+ export function defaultRunId(agentId: string, sendIndex: number): string {
293
+ return `run-${agentId}-${sendIndex + 1}`;
294
+ }
295
+
287
296
  export class ScriptedCursorAgent implements SDKAgent {
288
297
  readonly agentId: string;
289
298
  model: ModelSelection | undefined = undefined;
@@ -291,20 +300,37 @@ export class ScriptedCursorAgent implements SDKAgent {
291
300
  readonly runs: ScriptedRun[] = [];
292
301
  closeCalls = 0;
293
302
  private nextTurn = 0;
303
+ /** The scenario's scripts, one slot per send; `arrangeNextTurn` writes the slot the next send consumes. */
304
+ private readonly turns: TurnScript[];
294
305
 
295
306
  constructor(private readonly options: ScriptedAgentOptions) {
296
307
  this.agentId = options.agentId;
308
+ this.turns = [...options.turns];
309
+ }
310
+
311
+ /** The run id the NEXT `send()` will be given — so a script can be built with matching event ids before the send happens. */
312
+ get nextRunId(): string {
313
+ return this.options.runIds?.[this.nextTurn] ?? defaultRunId(this.agentId, this.nextTurn);
314
+ }
315
+
316
+ /**
317
+ * Set (or replace) what the NEXT `send()` plays. Scripts already consumed
318
+ * are untouched; a slot declared up front for a later send stays where it
319
+ * is.
320
+ */
321
+ arrangeNextTurn(script: TurnScript): void {
322
+ this.turns[this.nextTurn] = script;
297
323
  }
298
324
 
299
325
  async send(message: string | SDKUserMessage, options?: SendOptions): Promise<Run> {
300
- const script = this.options.turns[this.nextTurn];
326
+ const script = this.turns[this.nextTurn];
301
327
  if (!script) {
302
328
  throw new Error(
303
329
  `ScriptedCursorAgent ${this.agentId}: send() #${this.nextTurn + 1} has no script ` +
304
- `(the scenario declared ${this.options.turns.length})`,
330
+ `(the scenario declared ${this.turns.length})`,
305
331
  );
306
332
  }
307
- const runId = this.options.runIds?.[this.nextTurn] ?? `run-${this.agentId}-${this.nextTurn + 1}`;
333
+ const runId = this.nextRunId;
308
334
  this.nextTurn++;
309
335
  this.sends.push({ message, hasOnDelta: !!options?.onDelta });
310
336
  if (options?.model) this.model = options.model;
@@ -26,11 +26,18 @@
26
26
  * scenarios with different agents against the same mocked module.
27
27
  *
28
28
  * Resolution rules a scenario declares, mirroring what the real SDK does:
29
- * - `Agent.create` hands out the NEXT unclaimed agent in `agents` (turn 1 of a
30
- * fresh session; the fresh agent of a poisoned-handle recovery).
29
+ * - `Agent.create` hands out the agent declared for the session it is asked
30
+ * for (`agentForSession`, when the scenario resolves agents per session
31
+ * the harness contract kit runs several sessions concurrently on one
32
+ * adapter, and the order their creates arrive in is real I/O timing), else
33
+ * the NEXT unclaimed agent in `agents` (turn 1 of a fresh session; the fresh
34
+ * agent of a poisoned-handle recovery) — unless the scenario declared a
35
+ * `createFailure`, which the FIRST create throws instead (the SDK refusing
36
+ * to mint an agent: a 401 on the key, a validation error).
31
37
  * - `Agent.resume(id)` hands back the agent with that id if the scenario
32
- * declared it (in `agents` or `resumableAgents`), else throws `resolveAgent`
33
- * then falls back to `create`, which is the production shape of a lost handle.
38
+ * declared it (in `agents` or `resumableAgents`, or handed out for a
39
+ * session), else throws — `resolveAgent` then falls back to `create`, which
40
+ * is the production shape of a lost handle.
34
41
  * - `Cursor.models.list` answers the scenario's catalog.
35
42
  */
36
43
 
@@ -40,11 +47,29 @@ import type { ScriptedCursorAgent } from "./scripted-agent.js";
40
47
  export interface ScriptedSdkOptions {
41
48
  /** Agents handed out by `Agent.create`, in order. Also resumable by id. */
42
49
  readonly agents: readonly ScriptedCursorAgent[];
50
+ /**
51
+ * The agent `Agent.create` hands out for the session the create names,
52
+ * consulted before the ordered list. The SDK's create options carry the
53
+ * session as `platform.workspaceRef` (`session-lifecycle.ts`
54
+ * `resolvePlatformOptions`: `stigmer-session:<sessionId>`), so the resolver
55
+ * is keyed by that ref — a scenario computes the ref the same way the
56
+ * adapter does. `undefined` falls through to the list. Consulted live on
57
+ * every create, so a scenario may mint the session's agent only when it
58
+ * learns of the session.
59
+ */
60
+ readonly agentForWorkspaceRef?: (workspaceRef: string) => ScriptedCursorAgent | undefined;
43
61
  /**
44
62
  * Agents `Agent.resume` finds by id but `Agent.create` never hands out — a
45
63
  * previous turn's agent the session knows only by `harness_state_id`.
46
64
  */
47
65
  readonly resumableAgents?: readonly ScriptedCursorAgent[];
66
+ /**
67
+ * Thrown by the FIRST `Agent.create` instead of handing out an agent; later
68
+ * creates hand out `agents` as usual. A {@link ScriptedCursorSdkError} here is
69
+ * the SDK's own refusal (the activity's outer catch keys on `instanceof`);
70
+ * a plain `Error` is anything else that can escape the SDK boundary.
71
+ */
72
+ readonly createFailure?: Error;
48
73
  /** What `Cursor.models.list` answers. */
49
74
  readonly catalog: readonly ModelListItem[];
50
75
  }
@@ -56,19 +81,47 @@ export interface RecordedResolution {
56
81
  readonly options: Partial<AgentOptions> | undefined;
57
82
  }
58
83
 
84
+ /**
85
+ * The `platform.workspaceRef` a create names, read defensively: the platform
86
+ * option's type re-exports from the unshipped `@anysphere/cursor-sdk-local-runtime`
87
+ * and resolves to `any` under `skipLibCheck` (the same gap `scripted-agent.ts`
88
+ * records for the delta channel), so the shape is checked here, not assumed.
89
+ */
90
+ function workspaceRefOf(options: AgentOptions): string | undefined {
91
+ const platform: unknown = (options as { platform?: unknown }).platform;
92
+ if (typeof platform !== "object" || platform === null) return undefined;
93
+ const ref = (platform as { workspaceRef?: unknown }).workspaceRef;
94
+ return typeof ref === "string" ? ref : undefined;
95
+ }
96
+
59
97
  export class ScriptedCursorSdk {
60
98
  readonly resolutions: RecordedResolution[] = [];
61
99
  readonly archived: string[] = [];
62
100
  private nextCreate = 0;
101
+ private createFailurePending: boolean;
63
102
  private readonly byId = new Map<string, ScriptedCursorAgent>();
64
103
 
65
104
  constructor(private readonly options: ScriptedSdkOptions) {
66
105
  for (const a of [...options.agents, ...(options.resumableAgents ?? [])]) {
67
106
  this.byId.set(a.agentId, a);
68
107
  }
108
+ this.createFailurePending = options.createFailure !== undefined;
69
109
  }
70
110
 
71
111
  create(options: AgentOptions): SDKAgent {
112
+ if (this.createFailurePending && this.options.createFailure) {
113
+ this.createFailurePending = false;
114
+ this.resolutions.push({ kind: "create", agentId: undefined, options });
115
+ throw this.options.createFailure;
116
+ }
117
+ const workspaceRef = workspaceRefOf(options);
118
+ const forSession = workspaceRef !== undefined ? this.options.agentForWorkspaceRef?.(workspaceRef) : undefined;
119
+ if (forSession) {
120
+ this.byId.set(forSession.agentId, forSession);
121
+ forSession.model = options.model;
122
+ this.resolutions.push({ kind: "create", agentId: forSession.agentId, options });
123
+ return forSession;
124
+ }
72
125
  const agent = this.options.agents[this.nextCreate];
73
126
  if (!agent) {
74
127
  throw new Error(
@@ -101,20 +154,55 @@ export class ScriptedCursorSdk {
101
154
  }
102
155
  }
103
156
 
157
+ /** The construction options of the SDK's `CursorSdkError` (`errors.d.ts`), minus `cause`. */
158
+ export interface ScriptedCursorSdkErrorOptions {
159
+ readonly isRetryable?: boolean;
160
+ readonly code?: string;
161
+ readonly status?: number;
162
+ readonly endpoint?: string;
163
+ readonly requestId?: string;
164
+ readonly operation?: string;
165
+ }
166
+
104
167
  /**
105
168
  * The `CursorSdkError` the mocked module exports. A real `Error` subclass with
106
- * the two fields the classifier reads (`isRetryable`, `code`), under the SDK's
107
- * class name so `err.constructor.name` and `instanceof` (against THIS module's
108
- * export, which is what the activity's dynamic import resolves to) both hold.
169
+ * the SDK class's public surface (`@cursor/sdk` `errors.d.ts`: `isRetryable`,
170
+ * `code`, `status`, `endpoint`, `requestId`, `operation`, `toJSON()`), under
171
+ * the SDK's class name so `err.constructor.name` and `instanceof` (against
172
+ * THIS module's export, which is what the activity's dynamic import resolves
173
+ * to) both hold. The activity's outer catch reads `code`, `status` and
174
+ * `message` for the classifier and logs `toJSON()`; the double must carry the
175
+ * whole surface or the catch arm itself throws instead of mapping the error.
109
176
  */
110
177
  export class ScriptedCursorSdkError extends Error {
111
178
  readonly isRetryable: boolean;
112
179
  readonly code: string | undefined;
113
- constructor(message: string, opts: { isRetryable?: boolean; code?: string } = {}) {
180
+ readonly status: number | undefined;
181
+ readonly endpoint: string | undefined;
182
+ readonly requestId: string | undefined;
183
+ readonly operation: string | undefined;
184
+ constructor(message: string, opts: ScriptedCursorSdkErrorOptions = {}) {
114
185
  super(message);
115
186
  this.name = "CursorSdkError";
116
187
  this.isRetryable = opts.isRetryable ?? false;
117
188
  this.code = opts.code;
189
+ this.status = opts.status;
190
+ this.endpoint = opts.endpoint;
191
+ this.requestId = opts.requestId;
192
+ this.operation = opts.operation;
193
+ }
194
+
195
+ toJSON(): Record<string, unknown> {
196
+ return {
197
+ name: this.name,
198
+ message: this.message,
199
+ isRetryable: this.isRetryable,
200
+ code: this.code,
201
+ status: this.status,
202
+ endpoint: this.endpoint,
203
+ requestId: this.requestId,
204
+ operation: this.operation,
205
+ };
118
206
  }
119
207
  }
120
208
 
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Pins that the Cursor adapter is an SDK slice and nothing more: no
3
+ * production module under `activities/execute-cursor/` imports
4
+ * `@temporalio/*`.
5
+ *
6
+ * Why it matters: every Temporal fact a turn needs — the heartbeat, the
7
+ * cancellation, the throw the workflow sees — is the turn runtime's
8
+ * (`harness/run-turn.ts`) and reaches the adapter through the sink. The
9
+ * contract kit runs an adapter OUTSIDE any activity context
10
+ * (`__test-utils__/harness-contract/`), so a `Context.current()` anywhere
11
+ * in the adapter would throw there; and an adapter that threw a
12
+ * `CancelledFailure` would be deciding pause-vs-shutdown, which is the
13
+ * runtime's table. A static fence names the file in seconds where the kit
14
+ * would name it after a stack trace.
15
+ *
16
+ * Read off the syntax tree with the same primitive the import-direction
17
+ * fence uses (`__test-utils__/module-specifiers.ts`), so a package name in a
18
+ * comment cannot trip it and no import form can slip past it.
19
+ */
20
+
21
+ import { describe, it, expect } from "vitest";
22
+ import { join, relative } from "node:path";
23
+ import { fileURLToPath } from "node:url";
24
+
25
+ import { packageImports, readSource, typeScriptFilesUnder } from "../../../__test-utils__/module-specifiers.js";
26
+
27
+ const SRC_ROOT = fileURLToPath(new URL("../../../", import.meta.url));
28
+ const ADAPTER_ROOT = join(SRC_ROOT, "activities", "execute-cursor");
29
+
30
+ describe("the Cursor adapter never imports @temporalio", () => {
31
+ const files = typeScriptFilesUnder(ADAPTER_ROOT, new Set(["__tests__", "__test-utils__"]));
32
+ const offences = files.flatMap((file) =>
33
+ packageImports(file, readSource(file), "@temporalio").map((specifier) => ` ${relative(SRC_ROOT, file)} imports "${specifier}"`),
34
+ );
35
+
36
+ it("inspected the adapter's own files (the walk is rooted where it claims)", () => {
37
+ expect(files.map((f) => relative(ADAPTER_ROOT, f))).toEqual(
38
+ expect.arrayContaining(["adapter.ts", "turn.ts", "turn-setup.ts", "turn-stream.ts", "turn-settle.ts"]),
39
+ );
40
+ });
41
+
42
+ it("finds no @temporalio import in any production module", () => {
43
+ expect(offences, `the Cursor adapter must not import @temporalio/*:\n${offences.join("\n")}`).toEqual([]);
44
+ });
45
+ });