@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
@@ -8,9 +8,9 @@
8
8
  * vendor SDK — fetching the execution, resolving the blueprint and the
9
9
  * environment, provisioning and locking the workspace, mounting skills,
10
10
  * resolving MCP servers and approval policies, seeding the transcript, the
11
- * persist cadence, the stall watchdog, the Temporal heartbeat, pause vs
12
- * shutdown, the cost cap, the file-review boundary, the terminal mapping
13
- * is the RUNTIME's, written once. What a harness owns is its SDK slice: how
11
+ * persist chokepoint, the stall watchdog, the Temporal heartbeat, pause vs
12
+ * shutdown, the cost cap, the terminal mapping is the RUNTIME's
13
+ * (`run-turn.ts`), written once. What a harness owns is its SDK slice: how
14
14
  * the engine is created or resumed, how the prompt is placed, how MCP servers
15
15
  * are bound, how the engine is made to stop before a gated side effect, and
16
16
  * how its events become transcript rows. This file is the whole of what a
@@ -22,15 +22,15 @@
22
22
  * runtime cannot read anywhere else. Nothing here is speculative: where the
23
23
  * program's original sketch and the code disagreed, the code won, and the
24
24
  * disagreement was ruled at the entry's gate
25
- * (stigmer-cloud `_projects/2026-09/20260911.02.sp.harness-contract-and-kit/`).
25
+ * (stigmer-cloud `_projects/2026-09/20260911.02.sp.harness-contract-and-kit/`
26
+ * for S1; `20260911.03.sp.turn-runtime-extraction/` M3 for the growth below).
26
27
  *
27
28
  * What is deliberately NOT on this contract, and why:
28
29
  *
29
30
  * - No `dispose()`. One adapter object serves many concurrent turns
30
31
  * (`maxConcurrentActivities`), so a per-turn teardown method on the
31
32
  * adapter is a race. The adapter owns its per-turn teardown in its own
32
- * `finally` inside `runTurn` (the Cursor harness already parks its agent
33
- * there).
33
+ * `finally` inside `runTurn` (the Cursor harness parks its agent there).
34
34
  * - No `isCancelled()`, no `heartbeat(details)`, no `ExecutionStatusWriter`
35
35
  * base. Each would be a second way of saying something `stopSignal`,
36
36
  * `recordActivity()` or `requestPersist()` already says, and two writers of
@@ -46,17 +46,42 @@
46
46
  * - No `TurnInput.status`. The runtime seeds `TurnSink.status` from the
47
47
  * persisted transcript; a second copy on the input is the drift the
48
48
  * single-source-of-truth mandate forbids.
49
+ * - No execution context. "This activity is execution X" is the runtime's
50
+ * ambient fact for the WHOLE activity (`shared/execution-context.ts`, an
51
+ * `AsyncLocalStorage` the runtime enters before anything runs); the
52
+ * interceptors read it per request, so no adapter establishes or
53
+ * propagates it.
54
+ * - No persist cadence. The runtime's chokepoint is single-flight and
55
+ * unconditional at settle; WHEN a streaming turn asks for a write is the
56
+ * adapter's (`shared/persist-decision.ts` over its own dirty flags, since
57
+ * what counts as a discrete change is engine knowledge), until S3 lifts
58
+ * the file-review capture and can revisit with both loops in view.
49
59
  *
50
60
  * Module shape follows `shared/checkpointer/`: `types.ts`, `capabilities.ts`,
51
- * `registry.ts`, no barrel. Nothing production-facing imports this module
52
- * until the runtime that consumes it lands (S2 of the program).
61
+ * `registry.ts`, no barrel.
53
62
  */
54
63
 
55
64
  import type { ApprovalAction } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
56
- import type { AgentExecutionStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
65
+ import type { AgentExecution, AgentExecutionStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
66
+ import type { Session } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
57
67
 
58
68
  import type { Config } from "../config.js";
59
69
  import type { NormalizedActivityInput } from "../shared/activity-input.js";
70
+ import type { ArtifactStorage } from "../shared/artifact-storage.js";
71
+ import type { TimingRecorder } from "../shared/cold-start-timing.js";
72
+ import type { ResolvedBlueprint } from "../shared/blueprint-resolver.js";
73
+ import type { SessionWorkspaceProvision } from "../shared/workspace/session-provision.js";
74
+ import type { ResolvedMcpServer } from "../shared/mcp-resolver.js";
75
+ import type { ChannelMessagingInfo } from "../shared/channel-attachment.js";
76
+ import type { ActiveLeases, MergedToolPolicy } from "../shared/approval-policy.js";
77
+ import type { SkillMetadata } from "../shared/skill-resolver.js";
78
+ import type { ResolvedAttachment } from "../shared/attachment-resolver.js";
79
+ import type { NotViewableEntry, VisionImage } from "../shared/attachment-vision.js";
80
+ import type { EffectiveServiceTier } from "../shared/service-tier.js";
81
+ import type { EffectiveThinkingMode } from "../shared/thinking-mode.js";
82
+ import type { SenderIdentity } from "../shared/sender-identity.js";
83
+ import type { DeclaredPreferencesContent } from "../shared/declared-preferences.js";
84
+ import type { RecalledMemoriesContent } from "../shared/recalled-memories.js";
60
85
  import type { HarnessCapabilities } from "./capabilities.js";
61
86
 
62
87
  /**
@@ -115,9 +140,9 @@ export interface HarnessAdapter {
115
140
  * The rules every implementation is held to (the kit's invariants):
116
141
  *
117
142
  * - Resolves, never rejects. A vendor failure becomes
118
- * `{ kind: "failed", message }` with the user-facing sentence the
119
- * adapter's classifier produced. A `CancelledFailure` never escapes: the
120
- * runtime, not the adapter, decides what is a pause and what is a
143
+ * `{ kind: "failed", message, surface }` with the user-facing sentence
144
+ * the adapter's classifier produced. A `CancelledFailure` never escapes:
145
+ * the runtime, not the adapter, decides what is a pause and what is a
121
146
  * shutdown, and it throws exactly where Temporal semantics require.
122
147
  * - Stops promptly when `sink.stopSignal` aborts, whatever the cause,
123
148
  * settling `interrupted`. Every call the adapter makes is bounded: the
@@ -129,24 +154,104 @@ export interface HarnessAdapter {
129
154
  * `input.approvalDecisions`. APPROVE executes exactly once; REJECT and
130
155
  * SKIP never execute.
131
156
  * - Owns its own per-turn teardown in a `finally` inside this method.
157
+ * - Imports nothing from `@temporalio/*`: the kit runs an adapter outside
158
+ * any activity context, and every Temporal fact it needs arrives through
159
+ * the sink (`execute-cursor/__tests__/adapter-is-temporal-free.test.ts`).
132
160
  */
133
161
  runTurn(input: TurnInput, sink: TurnSink): Promise<TurnOutcome>;
134
162
  }
135
163
 
164
+ // ---------------------------------------------------------------------------
165
+ // The resolved record
166
+ // ---------------------------------------------------------------------------
167
+
168
+ /** The resolved environment (phase 2b): the MCP-bound env map and the keys that are secrets. */
169
+ export interface TurnEnvironment {
170
+ readonly envVars: Record<string, string>;
171
+ readonly secretKeys: ReadonlySet<string>;
172
+ }
173
+
174
+ /** The provisioned workspace (phase 2c) and the capture posture derived from it. */
175
+ export interface TurnWorkspace {
176
+ /** The directories the agent operates in; never empty (`provisionSessionWorkspace` guarantees it). */
177
+ readonly dirs: readonly string[];
178
+ /** `dirs[0]`, the tree the turn's lock, gate, capture and skill mount all key on. */
179
+ readonly primaryDir: string;
180
+ /** True when `primaryDir` is a git work tree: selects the git-diff capture substrate over CAS. */
181
+ readonly gitWorkspace: boolean;
182
+ /** Apply-then-review capture (true) or the classic deny-gate (false); see `shared/filereview/capture.ts` `deriveCaptureMode`. */
183
+ readonly captureMode: boolean;
184
+ /** `${executionId}:${turnSeq}`: the deterministic id of the change set this turn may produce. */
185
+ readonly changeSetId: string;
186
+ readonly provision: SessionWorkspaceProvision;
187
+ }
188
+
189
+ /** The tool surface (phases 4 to 4b): the resolved servers with the attachments folded in, and the merged approval policies. */
190
+ export interface TurnMcp {
191
+ /** Every resolved server, synthesized attachments included; the harness projects its SDK config from this list. */
192
+ readonly servers: readonly ResolvedMcpServer[];
193
+ /** Serving proactive channels and their templates (the DD-006 D2 discovery read). */
194
+ readonly channelMessaging: readonly ChannelMessagingInfo[];
195
+ readonly leases: ActiveLeases;
196
+ readonly policies: ReadonlyMap<string, MergedToolPolicy>;
197
+ }
198
+
199
+ /** The turn's explicit inputs (phase 5b), resolved into the workspace with the vision facts derived once. */
200
+ export interface TurnAttachments {
201
+ readonly results: readonly ResolvedAttachment[];
202
+ /** The images the model sees inline, in attachment order. */
203
+ readonly visionImages: readonly VisionImage[];
204
+ /** The image-shaped attachments that degraded to path-only, disclosed in the prompt. */
205
+ readonly visionNotViewable: readonly NotViewableEntry[];
206
+ }
207
+
208
+ /** What the execution asked for (phase 6, the harness-agnostic half): the raw model name and the effective tier and thinking mode. */
209
+ export interface TurnModelPreferences {
210
+ /** `spec.executionConfig.modelName`, or `"default"`; the harness validates it against its own catalog. */
211
+ readonly requested: string;
212
+ /** Never UNSPECIFIED: `resolveEffectiveServiceTier` is where the platform default is applied. */
213
+ readonly serviceTier: EffectiveServiceTier;
214
+ /** Never UNSPECIFIED: `resolveEffectiveThinkingMode` is where the platform default is applied. */
215
+ readonly thinkingMode: EffectiveThinkingMode;
216
+ }
217
+
136
218
  /**
137
- * What the runtime resolved for this turn and the adapter cannot read
138
- * anywhere else. This is the core; the runtime extraction (S2) grows it one
139
- * typed field per phase it takes over from the orchestrators (environment,
140
- * workspace, skills, MCP servers with merged policies, attachments, memory,
141
- * prompt bundle, model), in the `setup.ts` `SetupResult` mold.
219
+ * The standing context a first prompt carries (phase 9c) and the per-turn
220
+ * catchup, read once from the session metadata and the execution spec.
221
+ */
222
+ export interface TurnStandingContext {
223
+ readonly contextBridge: string | undefined;
224
+ readonly senderIdentity: SenderIdentity | undefined;
225
+ readonly sessionContext: string | undefined;
226
+ readonly declaredPreferences: DeclaredPreferencesContent | undefined;
227
+ readonly conversationCatchup: string | undefined;
228
+ /**
229
+ * The semantic memory selection, memoized to at most one run per
230
+ * invocation and stamping `status.recalledMemoriesReport` once. A thunk
231
+ * because only the harness knows whether its prompt carries standing
232
+ * context (a successfully resumed engine already holds it).
233
+ */
234
+ readonly selectRecalledMemories: () => Promise<RecalledMemoriesContent | undefined>;
235
+ }
236
+
237
+ /**
238
+ * Everything the runtime resolved for this turn, as small named groups
239
+ * (`turn-context.ts` produces one per phase; `run-turn.ts` composes them).
240
+ * This is the whole record: the runtime keeps nothing "private" beside it —
241
+ * the lock release and the write-back coordinator are the finally's
242
+ * resources (`run-turn.ts` `TurnFrame`), not facts about the turn.
142
243
  *
143
244
  * `threadId` is the engine's state id as the runtime knows it: empty on an
144
245
  * `engine-minted` harness's first turn (nothing minted yet) and the id the
145
246
  * adapter bound through {@link TurnSink.bindHarnessState} on every later
146
247
  * invocation; the runtime-minted id on every turn of a `deterministic`
147
- * harness. An adapter derives create-vs-resume from it and its own state; the
148
- * contract carries no `isReinvocation` flag because the two harnesses would
149
- * derive it differently.
248
+ * harness. An adapter derives create-vs-resume from it and its own state
249
+ * through `turn-context.ts`'s `isReinvocation`; the contract carries no flag
250
+ * because the two harnesses would derive it differently.
251
+ *
252
+ * Adapter-only facts (the Cursor mode, the service-tier params, the seeded
253
+ * sub-agent rows) are read by the adapter from these records, never resolved
254
+ * by the runtime.
150
255
  */
151
256
  export interface TurnInput extends NormalizedActivityInput {
152
257
  /**
@@ -166,12 +271,34 @@ export interface TurnInput extends NormalizedActivityInput {
166
271
  * verdict from the rows itself.
167
272
  */
168
273
  readonly approvalDecisions: ReadonlyMap<string, ApprovalAction>;
274
+ readonly execution: AgentExecution;
275
+ /** The same object as `blueprint.session`; `bindHarnessState` writes it. */
276
+ readonly session: Session;
277
+ readonly blueprint: ResolvedBlueprint;
278
+ readonly environment: TurnEnvironment;
279
+ readonly workspace: TurnWorkspace;
280
+ readonly mcp: TurnMcp;
281
+ /** The mounted skills (phase 5): each under the session's platform dir, reachable from the workspace through its `.stigmer` link; the harness renders them into its prompt. */
282
+ readonly skills: readonly SkillMetadata[];
283
+ readonly attachments: TurnAttachments;
284
+ /** Approved whole-file writes the runtime applied itself this turn (exact-apply); the harness issues no grant for them. */
285
+ readonly appliedToolCallIds: ReadonlySet<string>;
286
+ readonly model: TurnModelPreferences;
287
+ /** `spec.executionConfig.structuredOutputSchema`, when the execution asks for structured output. */
288
+ readonly structuredOutputSchema: Record<string, unknown> | undefined;
289
+ readonly standing: TurnStandingContext;
290
+ /** Resolved once by the runtime before any phase; absent when no substrate works. */
291
+ readonly artifactStorage: ArtifactStorage | undefined;
169
292
  }
170
293
 
294
+ // ---------------------------------------------------------------------------
295
+ // The sink
296
+ // ---------------------------------------------------------------------------
297
+
171
298
  /**
172
- * The runtime's face during one turn: the five things an adapter may ask of
173
- * it, and the one status it folds into. One sink per turn, owned by the
174
- * runtime; the adapter never constructs one.
299
+ * The runtime's face during one turn: what an adapter may ask of it, and the
300
+ * one status it folds into. One sink per turn, owned by the runtime; the
301
+ * adapter never constructs one.
175
302
  *
176
303
  * Field ownership on `status` before the canonical transcript lands (S4):
177
304
  * the adapter appends the engine's transcript rows (assistant messages,
@@ -179,7 +306,9 @@ export interface TurnInput extends NormalizedActivityInput {
179
306
  * runtime writes the phase, the terminal system messages, `streamingUsage`,
180
307
  * artifacts, write-backs and the file-review projection. An adapter never
181
308
  * writes a phase or a terminal copy: those are Temporal semantics the
182
- * runtime owns once.
309
+ * runtime owns once. (The file-review boundary itself is the adapter's until
310
+ * S3 lifts both harnesses' captures together; `execute-cursor/adapter.ts`
311
+ * says so.)
183
312
  */
184
313
  export interface TurnSink {
185
314
  /**
@@ -195,41 +324,74 @@ export interface TurnSink {
195
324
  * and maps the outcome; the adapter's only job is to settle promptly as
196
325
  * `interrupted`. `stopSignal.reason` is the runtime's own evidence — an
197
326
  * adapter never branches on it. Check `aborted` at every step boundary and
198
- * listen for `abort` inside anything long-running. May already be aborted
199
- * when `runTurn` is entered; then return `interrupted` before doing any
200
- * work.
327
+ * listen for `abort` inside anything long-running (the Cursor adapter
328
+ * cancels its SDK run from that listener). May already be aborted when
329
+ * `runTurn` is entered; then return `interrupted` before doing any work.
201
330
  */
202
331
  readonly stopSignal: AbortSignal;
203
332
 
204
333
  /**
205
- * "Persist the status soon": schedules a write through the runtime's single
206
- * persist chokepoint (tool-output offload, size cap, secret withholding,
207
- * the streaming scheduler). Fire and forget never awaited by the adapter,
208
- * never a promise. The runtime persists unconditionally when the turn
209
- * settles, so no adapter has to flush before returning.
334
+ * The runtime's cold-start timeline for this turn, a live handle like
335
+ * `status`. The runtime marked its own resolution segments on it before
336
+ * `runTurn`; the adapter marks its setup segments (skills, gate, engine
337
+ * resolve) and emits the `execution_setup` line once its engine is ready,
338
+ * so the one timeline reads end to end (`shared/cold-start-timing.ts`).
339
+ * Diagnostics only; nothing branches on it.
340
+ */
341
+ readonly setupTiming: TimingRecorder;
342
+
343
+ /**
344
+ * "Persist the status": a write through the runtime's single persist
345
+ * chokepoint (tool-output offload, size cap, secret withholding,
346
+ * `streamingUsage`). Single-flight: a request while a write is in flight
347
+ * coalesces into the next write. Resolves when the state as of the request
348
+ * has been written, so an adapter that needs ordering MAY await it (the
349
+ * Cursor loop awaits before pulling the next event, so a platform STOP
350
+ * answered by that write stops the turn before the next event, as it
351
+ * always has); an adapter never MUST await it, because the runtime
352
+ * persists unconditionally when the turn settles. Never rejects.
210
353
  */
211
- requestPersist(): void;
354
+ requestPersist(): Promise<void>;
212
355
 
213
356
  /**
214
357
  * "I made progress": resets the runtime's stall watchdog and is carried
215
- * into the next Temporal heartbeat. Call it on every engine event and every
216
- * token delta a long generation emits deltas but few discrete events, and
217
- * resetting only on events false-positives a stall. Never throws.
358
+ * into the next Temporal heartbeat. Call it on every engine event, every
359
+ * token delta, and every step boundary of the adapter's own setup (engine
360
+ * resolved, send returned, boundary done) a long generation emits deltas
361
+ * but few discrete events, and resetting only on events false-positives a
362
+ * stall. `detail` names what progressed (the Cursor loop passes the tool
363
+ * name of a `tool_call` event); the runtime quotes the last detail in the
364
+ * stall diagnostic (`last tool: shell`). Never throws.
218
365
  */
219
- recordActivity(): void;
366
+ recordActivity(detail?: string): void;
220
367
 
221
368
  /**
222
- * Token counts for one engine turn. The runtime accumulates, prices and
223
- * enforces `max_cost_usd`; an adapter reports and never accounts. Every
224
- * count is a non-negative delta since the previous report.
369
+ * Token counts for one engine turn, priced by the adapter against its own
370
+ * vendor's table. The runtime accumulates and enforces `max_cost_usd`; an
371
+ * adapter reports and never accounts. Every count is a non-negative delta
372
+ * since the previous report.
225
373
  */
226
374
  reportUsage(delta: UsageDelta): void;
227
375
 
376
+ /**
377
+ * The user-visible setup label (`status.setupProgress.currentPhase`) for a
378
+ * step only the adapter knows ("Initializing Cursor agent"). The runtime
379
+ * reports its own resolution labels itself; the adapter reports the labels
380
+ * of its setup steps exactly as the orchestrator did, so the UI's spinner
381
+ * copy is unchanged by the extraction (Q-S2-5). Resolves once the label is
382
+ * written; the write carries no phase, so it never advances the execution.
383
+ */
384
+ reportProgress(label: string): Promise<void>;
385
+
228
386
  /**
229
387
  * The engine-minted state id, the moment it exists and BEFORE the turn
230
388
  * proceeds, so a crash mid-turn still resumes on the next invocation. The
231
- * runtime writes it to the session at once (the Cursor harness's
232
- * `harness_state_id`). Called only by adapters whose
389
+ * runtime writes it to the session record the adapter was handed
390
+ * (`input.session`, with `harness_state_id` set and the metadata slug
391
+ * cleared, the agnostic quirk of `BuildUpdateStateStep`); the adapter may
392
+ * set its own harness-specific `SessionSpec` fields on that record before
393
+ * binding, one writer per field (`harnessStateId` the runtime's,
394
+ * `cursorMode` the adapter's; Q-S2-11). Called only by adapters whose
233
395
  * `capabilities.stateIdSource` is `"engine-minted"`, and before their first
234
396
  * `requestPersist`; a `deterministic` harness never calls it. Rejects when
235
397
  * the session write fails; the adapter then ends the turn `failed` with
@@ -239,40 +401,73 @@ export interface TurnSink {
239
401
  }
240
402
 
241
403
  /**
242
- * Token counts for one engine turn, as the Cursor loop reads them from the
243
- * SDK's `turn-ended` delta (`execute-cursor/usage-accumulator.ts`
244
- * `TurnUsage` is this shape; the runtime extraction collapses the two). Every
245
- * field is optional because engines report different subsets; a missing
246
- * field means zero, never "unknown".
404
+ * Token counts for one engine turn, priced. The four counts are what the
405
+ * Cursor loop reads from the SDK's `turn-ended` delta; `estimatedCostUsd` is
406
+ * the adapter's price for them at its vendor's rates (the runtime cannot
407
+ * price without the vendor's table and must not import it; Q-S2-12), and
408
+ * `model` / `requestedModelParams` name the basis it priced against, which
409
+ * the runtime records into `streamingUsage` (`model` is the catalog-validated
410
+ * id, `requestedModelParams` the JSON of the params sent — a string on the
411
+ * proto, so the SDK type stays inside the adapter). Every field is optional
412
+ * because engines report different subsets; a missing count means zero,
413
+ * never "unknown"; a missing basis inherits the previous delta's.
247
414
  */
248
415
  export interface UsageDelta {
249
416
  readonly inputTokens?: number;
250
417
  readonly outputTokens?: number;
251
418
  readonly cacheReadTokens?: number;
252
419
  readonly cacheWriteTokens?: number;
420
+ readonly estimatedCostUsd?: number;
421
+ readonly model?: string;
422
+ readonly requestedModelParams?: string;
253
423
  }
254
424
 
425
+ /**
426
+ * Which of the runtime's three failure copies a `failed` outcome takes. A
427
+ * classification, never copy: the runtime owns the words
428
+ * (`terminal-table.ts`), the adapter says what kind of thing failed.
429
+ *
430
+ * - `engine`: the engine reported its run as failed. The transcript already
431
+ * tells the story, so the runtime writes `status.error` and no system row
432
+ * (the Cursor `run.wait()` error arm).
433
+ * - `actionable`: the user can fix it (a foreign hook blocked a tool). One
434
+ * `Execution failed: …` row, the same shape the runtime's own settlements
435
+ * use.
436
+ * - `internal`: the runner or its transport broke unexpectedly (a thrown
437
+ * SDK error, an exception in the adapter). The boilerplate row and an
438
+ * `Error details:` row.
439
+ */
440
+ export type FailureSurface = "engine" | "actionable" | "internal";
441
+
255
442
  /**
256
443
  * How one turn ended, carrying ONLY what the runtime cannot read from
257
444
  * `sink.status` or its own evidence.
258
445
  *
259
446
  * - `completed`: the engine finished. The final text and any structured
260
447
  * output are already folded onto the status; nothing rides here.
448
+ * - `cancelled`: the engine ended its own run cancelled and there is nothing
449
+ * to wait for — an SDK-side cancel, or a deny-and-retry adapter that
450
+ * stopped its run to gate a call and then found nothing to pause for
451
+ * (an unattended denial settled as skipped). Not `interrupted`: the
452
+ * runtime's `stopSignal` never fired. The runtime writes
453
+ * `EXECUTION_CANCELLED` with no copy and completes the turn.
261
454
  * - `awaiting_approval`: the engine proposed at least one gated side effect
262
455
  * and stopped. The WAITING_APPROVAL rows are already on the status; the
263
456
  * runtime persists them and returns to the workflow, which reinvokes with
264
457
  * the decisions.
265
458
  * - `failed`: the engine or its transport failed in a way the adapter can
266
- * name. `message` is the user-facing sentence; `cause` is for the log.
267
- * The runtime persists FAILED and RETURNS (Temporal does not retry a
268
- * returned activity; re-running the same prompt would fail the same way).
459
+ * name. `message` is the user-facing sentence, `surface` which copy it
460
+ * takes, `cause` is for the log. The runtime persists FAILED and RETURNS
461
+ * (Temporal does not retry a returned activity; re-running the same
462
+ * prompt would fail the same way).
269
463
  * - `interrupted`: `sink.stopSignal` aborted and the adapter stopped. WHY it
270
464
  * aborted is the runtime's evidence (its watchdog, its accounting, its
271
- * heartbeat, its shutdown signal), so no reason rides here; the runtime
272
- * classifies and applies the throw-vs-return table.
465
+ * chokepoint, the cancellation it was delivered), so no reason rides here;
466
+ * the runtime classifies and applies the throw-vs-return table.
273
467
  */
274
468
  export type TurnOutcome =
275
469
  | { readonly kind: "completed" }
470
+ | { readonly kind: "cancelled" }
276
471
  | { readonly kind: "awaiting_approval" }
277
- | { readonly kind: "failed"; readonly message: string; readonly cause?: unknown }
472
+ | { readonly kind: "failed"; readonly message: string; readonly surface: FailureSurface; readonly cause?: unknown }
278
473
  | { readonly kind: "interrupted" };
@@ -0,0 +1,122 @@
1
+ /**
2
+ * The turn runtime's usage accounting: the priced deltas an adapter reports
3
+ * through `TurnSink.reportUsage`, summed into the `streaming_usage` summary
4
+ * the persist chokepoint writes before every status write, and the running
5
+ * cost the `max_cost_usd` cap is enforced against.
6
+ *
7
+ * Who owns what (Q-S2-12): the ADAPTER prices, because only it has its
8
+ * vendor's rate table and variant semantics (`execute-cursor/usage-pricing.ts`
9
+ * for Cursor); the RUNTIME accounts and enforces, because the cap and the
10
+ * summary are the platform's, the same for every engine. A delta therefore
11
+ * arrives already priced, naming the basis it was priced against (`model`,
12
+ * `requestedModelParams`), and this class adds — it never multiplies. The
13
+ * tier and thinking mode it records are the runtime's own effective
14
+ * preferences (`TurnInput.model`), the audit trail that the account default
15
+ * was never left in control (#357, #772).
16
+ *
17
+ * Moved from `activities/execute-cursor/usage-accumulator.ts` at S2 M3, the
18
+ * pricing call split out; the sums, the snapshot shape and the empty
19
+ * snapshot are unchanged, so `streamingUsage` is byte-for-byte what the
20
+ * Cursor orchestrator wrote.
21
+ *
22
+ * This data is display-only. The authoritative billing source is the BiDi
23
+ * proxy, which records usage from the wire.
24
+ */
25
+
26
+ import { ServiceTier, ThinkingMode } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
27
+
28
+ import type { UsageDelta } from "./types.js";
29
+
30
+ export interface UsageSnapshot {
31
+ readonly inputTokens: bigint;
32
+ readonly outputTokens: bigint;
33
+ readonly cacheReadTokens: bigint;
34
+ readonly cacheWriteTokens: bigint;
35
+ readonly totalTokens: bigint;
36
+ readonly turnCount: number;
37
+ readonly estimatedCostUsd: number;
38
+ /** The basis the adapter last priced against (its catalog-validated model id); `""` until a delta names one. */
39
+ readonly model: string;
40
+ readonly observedAt: string;
41
+ /** Tier the runner requested — always explicit post-translation (#357). */
42
+ readonly requestedServiceTier: ServiceTier;
43
+ /** JSON-encoded params the adapter sent with its model selection; "" when none. */
44
+ readonly requestedModelParams: string;
45
+ /** Thinking mode the runner requested — always explicit post-translation (#772). */
46
+ readonly requestedThinkingMode: ThinkingMode;
47
+ }
48
+
49
+ const EMPTY_SNAPSHOT: UsageSnapshot = {
50
+ inputTokens: 0n,
51
+ outputTokens: 0n,
52
+ cacheReadTokens: 0n,
53
+ cacheWriteTokens: 0n,
54
+ totalTokens: 0n,
55
+ turnCount: 0,
56
+ estimatedCostUsd: 0,
57
+ model: "",
58
+ observedAt: "",
59
+ requestedServiceTier: ServiceTier.UNSPECIFIED,
60
+ requestedModelParams: "",
61
+ requestedThinkingMode: ThinkingMode.UNSPECIFIED,
62
+ };
63
+
64
+ export class UsageAccumulator {
65
+ private inputTokens = 0;
66
+ private outputTokens = 0;
67
+ private cacheReadTokens = 0;
68
+ private cacheWriteTokens = 0;
69
+ private turnCount = 0;
70
+ private estimatedCostUsd = 0;
71
+ private observedAt = "";
72
+ private model = "";
73
+ private requestedModelParams = "";
74
+
75
+ constructor(
76
+ /** The effective tier the runtime resolved (never UNSPECIFIED on a real turn; the default keeps the empty snapshot honest). */
77
+ private readonly requestedServiceTier: ServiceTier = ServiceTier.UNSPECIFIED,
78
+ /** The effective thinking mode the runtime resolved. Price-neutral (#772); recorded purely as the audit trail twin of the tier. */
79
+ private readonly requestedThinkingMode: ThinkingMode = ThinkingMode.UNSPECIFIED,
80
+ ) {}
81
+
82
+ /** Add one priced delta. A delta without a basis inherits the previous one; a missing count is zero. */
83
+ addTurn(delta: UsageDelta): void {
84
+ this.inputTokens += delta.inputTokens ?? 0;
85
+ this.outputTokens += delta.outputTokens ?? 0;
86
+ this.cacheReadTokens += delta.cacheReadTokens ?? 0;
87
+ this.cacheWriteTokens += delta.cacheWriteTokens ?? 0;
88
+ this.estimatedCostUsd += delta.estimatedCostUsd ?? 0;
89
+ if (delta.model !== undefined) this.model = delta.model;
90
+ if (delta.requestedModelParams !== undefined) this.requestedModelParams = delta.requestedModelParams;
91
+ this.turnCount++;
92
+ this.observedAt = new Date().toISOString();
93
+ }
94
+
95
+ get hasTurns(): boolean {
96
+ return this.turnCount > 0;
97
+ }
98
+
99
+ snapshot(): UsageSnapshot {
100
+ if (this.turnCount === 0) return EMPTY_SNAPSHOT;
101
+
102
+ return {
103
+ inputTokens: BigInt(this.inputTokens),
104
+ outputTokens: BigInt(this.outputTokens),
105
+ cacheReadTokens: BigInt(this.cacheReadTokens),
106
+ cacheWriteTokens: BigInt(this.cacheWriteTokens),
107
+ // The Cursor SDK follows Anthropic's convention: inputTokens already
108
+ // INCLUDES the cached portions (cacheReadTokens/cacheWriteTokens are
109
+ // subsets of it, not additive). The true total throughput is therefore
110
+ // inputTokens + outputTokens. Adding the cache buckets again would
111
+ // double-count them and inflate the figure the Usage widget shows.
112
+ totalTokens: BigInt(this.inputTokens + this.outputTokens),
113
+ turnCount: this.turnCount,
114
+ estimatedCostUsd: this.estimatedCostUsd,
115
+ model: this.model,
116
+ observedAt: this.observedAt,
117
+ requestedServiceTier: this.requestedServiceTier,
118
+ requestedModelParams: this.requestedModelParams,
119
+ requestedThinkingMode: this.requestedThinkingMode,
120
+ };
121
+ }
122
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The harnesses this worker serves: one registry row per adapter, in boot
3
+ * order. The ONE place an adapter's factory is named outside its own
4
+ * directory.
5
+ *
6
+ * Lives at the source root, beside the composition roots that read it, and
7
+ * not in `harness/registry.ts`: a row imports its adapter from
8
+ * `activities/`, and nothing under `src/harness/` may
9
+ * (`harness/__tests__/import-direction.test.ts`; the rule the turn runtime
10
+ * is written under). The registry knows rows, never which adapters exist.
11
+ *
12
+ * ORDER IS LOAD-BEARING (`registry.ts` `bootHarnesses`): the Cursor
13
+ * adapter's interceptors must patch `node:http2` before anything dials the
14
+ * control plane, so it boots first. The native deep-agent harness joins this
15
+ * table at S3 of the harness runtime program; until then both roots import
16
+ * its activities directly beside this table's.
17
+ *
18
+ * THIS MODULE'S STATIC GRAPH MUST STAY CONNECT- AND SDK-FREE. The roots
19
+ * import it BEFORE they boot the harnesses, and the Cursor adapter's boot is
20
+ * where `node:http2` is patched and `@cursor/sdk` first loaded; an adapter
21
+ * factory that imported its SDK statically would defeat both. An adapter
22
+ * named here loads its vendor SDK inside `boot` (`adapter.ts` shows the
23
+ * shape). `__tests__/harness-boot-order.test.ts` boots a fresh process
24
+ * through this module and fails if the graph regresses.
25
+ */
26
+
27
+ import { createCursorAdapter } from "./activities/execute-cursor/adapter.js";
28
+ import type { HarnessRow } from "./harness/registry.js";
29
+
30
+ export const HARNESS_ADAPTERS: readonly HarnessRow[] = [{ harness: "cursor", adapter: createCursorAdapter() }];
package/src/main.ts CHANGED
@@ -44,7 +44,7 @@ import { decidePoolBoot, registerPoolMemberContext } from "./pool-member.js";
44
44
  import { buildReadyMessage } from "./ipc-protocol.js";
45
45
  import type { IpcCommand, IpcResponse } from "./ipc-protocol.js";
46
46
 
47
- import { handleUnhandledRejection, setExecutionContextRef } from "./activities/execute-cursor/rejection-capture.js";
47
+ import { handleUnhandledRejection } from "./activities/execute-cursor/rejection-capture.js";
48
48
  import { installProcessPipeGuards, reportFatal } from "./pipe-safety.js";
49
49
 
50
50
  // Guard the host pipes before anything writes to them. A dropped stderr/stdout