@stigmer/runner 3.15.0 → 3.15.2-dev.20260913223433

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 (518) hide show
  1. package/README.md +2 -4
  2. package/dist/.build-fingerprint +1 -1
  3. package/dist/__test-utils__/execution-record-fixture.d.ts +14 -0
  4. package/dist/__test-utils__/execution-record-fixture.js +4 -0
  5. package/dist/__test-utils__/execution-record-fixture.js.map +1 -1
  6. package/dist/__test-utils__/file-review-projection.d.ts +40 -0
  7. package/dist/__test-utils__/file-review-projection.js +136 -0
  8. package/dist/__test-utils__/file-review-projection.js.map +1 -0
  9. package/dist/__test-utils__/harness-contract/types.d.ts +23 -1
  10. package/dist/__test-utils__/harness-contract/types.js +15 -0
  11. package/dist/__test-utils__/harness-contract/types.js.map +1 -1
  12. package/dist/__test-utils__/hermetic-activity.d.ts +44 -12
  13. package/dist/__test-utils__/hermetic-activity.js +52 -14
  14. package/dist/__test-utils__/hermetic-activity.js.map +1 -1
  15. package/dist/__test-utils__/model-registry-fixture.d.ts +32 -7
  16. package/dist/__test-utils__/model-registry-fixture.js +31 -7
  17. package/dist/__test-utils__/model-registry-fixture.js.map +1 -1
  18. package/dist/__test-utils__/turn-input-fixture.d.ts +1 -1
  19. package/dist/__test-utils__/turn-input-fixture.js +1 -1
  20. package/dist/__test-utils__/turn-input-fixture.js.map +1 -1
  21. package/dist/activities/call-agent.js +2 -2
  22. package/dist/activities/call-agent.js.map +1 -1
  23. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js +45 -3
  24. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js.map +1 -1
  25. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +0 -9
  26. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +2 -41
  27. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
  28. package/dist/activities/execute-cursor/adapter.d.ts +7 -5
  29. package/dist/activities/execute-cursor/adapter.js +7 -5
  30. package/dist/activities/execute-cursor/adapter.js.map +1 -1
  31. package/dist/activities/execute-cursor/approval-policy.d.ts +5 -2
  32. package/dist/activities/execute-cursor/approval-policy.js +5 -2
  33. package/dist/activities/execute-cursor/approval-policy.js.map +1 -1
  34. package/dist/activities/execute-cursor/approval-state.d.ts +16 -8
  35. package/dist/activities/execute-cursor/approval-state.js +6 -3
  36. package/dist/activities/execute-cursor/approval-state.js.map +1 -1
  37. package/dist/activities/execute-cursor/cas-observations.d.ts +14 -2
  38. package/dist/activities/execute-cursor/cas-observations.js +19 -2
  39. package/dist/activities/execute-cursor/cas-observations.js.map +1 -1
  40. package/dist/activities/execute-cursor/cursor-capabilities.d.ts +8 -4
  41. package/dist/activities/execute-cursor/cursor-capabilities.js +21 -4
  42. package/dist/activities/execute-cursor/cursor-capabilities.js.map +1 -1
  43. package/dist/activities/execute-cursor/message-translator.d.ts +12 -20
  44. package/dist/activities/execute-cursor/message-translator.js +19 -32
  45. package/dist/activities/execute-cursor/message-translator.js.map +1 -1
  46. package/dist/activities/execute-cursor/prompt-builder.d.ts +48 -58
  47. package/dist/activities/execute-cursor/prompt-builder.js +76 -95
  48. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  49. package/dist/activities/execute-cursor/turn-boundary.d.ts +27 -55
  50. package/dist/activities/execute-cursor/turn-boundary.js +30 -90
  51. package/dist/activities/execute-cursor/turn-boundary.js.map +1 -1
  52. package/dist/activities/execute-cursor/turn-settle.d.ts +11 -7
  53. package/dist/activities/execute-cursor/turn-settle.js +37 -49
  54. package/dist/activities/execute-cursor/turn-settle.js.map +1 -1
  55. package/dist/activities/execute-cursor/turn-setup.d.ts +16 -24
  56. package/dist/activities/execute-cursor/turn-setup.js +29 -59
  57. package/dist/activities/execute-cursor/turn-setup.js.map +1 -1
  58. package/dist/activities/execute-cursor/turn-stream.d.ts +3 -8
  59. package/dist/activities/execute-cursor/turn-stream.js +9 -22
  60. package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
  61. package/dist/activities/execute-cursor/turn.js +5 -1
  62. package/dist/activities/execute-cursor/turn.js.map +1 -1
  63. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.d.ts +93 -0
  64. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js +348 -0
  65. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js.map +1 -0
  66. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.d.ts +170 -0
  67. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js +225 -0
  68. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js.map +1 -0
  69. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.d.ts +24 -0
  70. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js +41 -0
  71. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js.map +1 -0
  72. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.d.ts +54 -0
  73. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js +72 -0
  74. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js.map +1 -0
  75. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.d.ts +187 -23
  76. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js +238 -27
  77. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js.map +1 -1
  78. package/dist/activities/execute-deep-agent/adapter.d.ts +41 -0
  79. package/dist/activities/execute-deep-agent/adapter.js +78 -0
  80. package/dist/activities/execute-deep-agent/adapter.js.map +1 -0
  81. package/dist/activities/execute-deep-agent/cas-capture-observer.d.ts +8 -0
  82. package/dist/activities/execute-deep-agent/cas-capture-observer.js +9 -0
  83. package/dist/activities/execute-deep-agent/cas-capture-observer.js.map +1 -1
  84. package/dist/activities/execute-deep-agent/deep-agent-capabilities.d.ts +31 -0
  85. package/dist/activities/execute-deep-agent/deep-agent-capabilities.js +40 -0
  86. package/dist/activities/execute-deep-agent/deep-agent-capabilities.js.map +1 -0
  87. package/dist/activities/execute-deep-agent/execution-state.d.ts +4 -11
  88. package/dist/activities/execute-deep-agent/execution-state.js +4 -12
  89. package/dist/activities/execute-deep-agent/execution-state.js.map +1 -1
  90. package/dist/activities/execute-deep-agent/hitl.d.ts +49 -47
  91. package/dist/activities/execute-deep-agent/hitl.js +77 -103
  92. package/dist/activities/execute-deep-agent/hitl.js.map +1 -1
  93. package/dist/activities/execute-deep-agent/prompt-builder.d.ts +51 -23
  94. package/dist/activities/execute-deep-agent/prompt-builder.js +115 -76
  95. package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
  96. package/dist/activities/execute-deep-agent/status-builder-shared.d.ts +18 -32
  97. package/dist/activities/execute-deep-agent/status-builder-shared.js +10 -65
  98. package/dist/activities/execute-deep-agent/status-builder-shared.js.map +1 -1
  99. package/dist/activities/execute-deep-agent/streaming-side-effects.d.ts +10 -8
  100. package/dist/activities/execute-deep-agent/streaming-side-effects.js +12 -14
  101. package/dist/activities/execute-deep-agent/streaming-side-effects.js.map +1 -1
  102. package/dist/activities/execute-deep-agent/subagent-tracker.d.ts +36 -13
  103. package/dist/activities/execute-deep-agent/subagent-tracker.js +76 -39
  104. package/dist/activities/execute-deep-agent/subagent-tracker.js.map +1 -1
  105. package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +25 -28
  106. package/dist/activities/execute-deep-agent/subagent-transformer.js +29 -82
  107. package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
  108. package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +3 -2
  109. package/dist/activities/execute-deep-agent/subagent-wiring.js +2 -2
  110. package/dist/activities/execute-deep-agent/subagent-wiring.js.map +1 -1
  111. package/dist/activities/execute-deep-agent/turn-settle.d.ts +42 -0
  112. package/dist/activities/execute-deep-agent/turn-settle.js +146 -0
  113. package/dist/activities/execute-deep-agent/turn-settle.js.map +1 -0
  114. package/dist/activities/execute-deep-agent/turn-setup.d.ts +212 -0
  115. package/dist/activities/execute-deep-agent/turn-setup.js +430 -0
  116. package/dist/activities/execute-deep-agent/turn-setup.js.map +1 -0
  117. package/dist/activities/execute-deep-agent/turn-stream.d.ts +97 -0
  118. package/dist/activities/execute-deep-agent/turn-stream.js +242 -0
  119. package/dist/activities/execute-deep-agent/turn-stream.js.map +1 -0
  120. package/dist/activities/execute-deep-agent/turn.d.ts +42 -0
  121. package/dist/activities/execute-deep-agent/turn.js +116 -0
  122. package/dist/activities/execute-deep-agent/turn.js.map +1 -0
  123. package/dist/activities/execute-deep-agent/v3-event-recorder.d.ts +6 -5
  124. package/dist/activities/execute-deep-agent/v3-event-recorder.js +6 -5
  125. package/dist/activities/execute-deep-agent/v3-event-recorder.js.map +1 -1
  126. package/dist/activities/execute-deep-agent/v3-events.d.ts +1 -1
  127. package/dist/activities/execute-deep-agent/v3-events.js +1 -1
  128. package/dist/activities/execute-deep-agent/v3-status-builder.d.ts +60 -17
  129. package/dist/activities/execute-deep-agent/v3-status-builder.js +72 -57
  130. package/dist/activities/execute-deep-agent/v3-status-builder.js.map +1 -1
  131. package/dist/harness/approval-decisions.d.ts +61 -0
  132. package/dist/harness/approval-decisions.js +102 -0
  133. package/dist/harness/approval-decisions.js.map +1 -0
  134. package/dist/harness/capabilities.d.ts +16 -5
  135. package/dist/harness/capabilities.js +9 -0
  136. package/dist/harness/capabilities.js.map +1 -1
  137. package/dist/harness/capture.d.ts +144 -0
  138. package/dist/harness/capture.js +219 -0
  139. package/dist/harness/capture.js.map +1 -0
  140. package/dist/harness/persist-chokepoint.d.ts +19 -4
  141. package/dist/harness/persist-chokepoint.js +17 -4
  142. package/dist/harness/persist-chokepoint.js.map +1 -1
  143. package/dist/harness/run-turn.js +115 -29
  144. package/dist/harness/run-turn.js.map +1 -1
  145. package/dist/harness/terminal-table.d.ts +40 -11
  146. package/dist/harness/terminal-table.js +58 -19
  147. package/dist/harness/terminal-table.js.map +1 -1
  148. package/dist/harness/turn-context.d.ts +141 -76
  149. package/dist/harness/turn-context.js +194 -99
  150. package/dist/harness/turn-context.js.map +1 -1
  151. package/dist/harness/types.d.ts +65 -12
  152. package/dist/harness/types.js +8 -2
  153. package/dist/harness/types.js.map +1 -1
  154. package/dist/harness-adapters.d.ts +12 -8
  155. package/dist/harness-adapters.js +17 -9
  156. package/dist/harness-adapters.js.map +1 -1
  157. package/dist/middleware/approval-gate.d.ts +1 -1
  158. package/dist/middleware/approval-gate.js +1 -1
  159. package/dist/middleware/approval-gate.js.map +1 -1
  160. package/dist/middleware/cost-advisory.d.ts +39 -0
  161. package/dist/middleware/{cost-cap.js → cost-advisory.js} +37 -55
  162. package/dist/middleware/cost-advisory.js.map +1 -0
  163. package/dist/middleware/index.d.ts +23 -12
  164. package/dist/middleware/index.js +26 -18
  165. package/dist/middleware/index.js.map +1 -1
  166. package/dist/middleware/types.d.ts +3 -2
  167. package/dist/runner-manager.js +1 -5
  168. package/dist/runner-manager.js.map +1 -1
  169. package/dist/runner.js +1 -5
  170. package/dist/runner.js.map +1 -1
  171. package/dist/shared/attachment-resolver.d.ts +41 -18
  172. package/dist/shared/attachment-resolver.js +178 -46
  173. package/dist/shared/attachment-resolver.js.map +1 -1
  174. package/dist/shared/attachment-zip.d.ts +85 -0
  175. package/dist/shared/attachment-zip.js +185 -0
  176. package/dist/shared/attachment-zip.js.map +1 -0
  177. package/dist/shared/connect-backfill.js +5 -4
  178. package/dist/shared/connect-backfill.js.map +1 -1
  179. package/dist/shared/cost-guard.d.ts +3 -3
  180. package/dist/shared/cost-guard.js +3 -3
  181. package/dist/shared/execution-status-writer.d.ts +5 -5
  182. package/dist/shared/execution-status-writer.js +5 -5
  183. package/dist/shared/extract-structured-output.d.ts +8 -7
  184. package/dist/shared/extract-structured-output.js +8 -7
  185. package/dist/shared/extract-structured-output.js.map +1 -1
  186. package/dist/shared/filereview/cas-progress.d.ts +1 -18
  187. package/dist/shared/filereview/cas-progress.js +4 -0
  188. package/dist/shared/filereview/cas-progress.js.map +1 -1
  189. package/dist/shared/filereview/cas-touched.d.ts +56 -0
  190. package/dist/shared/filereview/cas-touched.js +63 -0
  191. package/dist/shared/filereview/cas-touched.js.map +1 -0
  192. package/dist/shared/filereview/index.d.ts +2 -1
  193. package/dist/shared/filereview/index.js +2 -1
  194. package/dist/shared/filereview/index.js.map +1 -1
  195. package/dist/shared/mcp-resolver.d.ts +4 -5
  196. package/dist/shared/mcp-resolver.js +4 -5
  197. package/dist/shared/mcp-resolver.js.map +1 -1
  198. package/dist/shared/persist-decision.d.ts +3 -4
  199. package/dist/shared/persist-decision.js +3 -4
  200. package/dist/shared/persist-decision.js.map +1 -1
  201. package/dist/shared/plan-mode-permissions.d.ts +2 -2
  202. package/dist/shared/plan-mode-permissions.js +2 -2
  203. package/dist/shared/plan-mode-prompt.d.ts +1 -1
  204. package/dist/shared/plan-mode-prompt.js +1 -1
  205. package/dist/shared/prompt-sections.d.ts +163 -0
  206. package/dist/shared/prompt-sections.js +164 -0
  207. package/dist/shared/prompt-sections.js.map +1 -0
  208. package/dist/shared/skill-resolver.d.ts +4 -2
  209. package/dist/shared/skill-resolver.js +4 -2
  210. package/dist/shared/skill-resolver.js.map +1 -1
  211. package/dist/shared/tool-rounds.d.ts +32 -0
  212. package/dist/shared/tool-rounds.js +43 -0
  213. package/dist/shared/tool-rounds.js.map +1 -1
  214. package/dist/shared/tool-row.d.ts +34 -0
  215. package/dist/shared/tool-row.js +52 -0
  216. package/dist/shared/tool-row.js.map +1 -1
  217. package/dist/shared/workspace/session-provision.d.ts +3 -3
  218. package/dist/shared/workspace/session-provision.js +3 -3
  219. package/dist/shared/workspace/stigmer-link.d.ts +3 -3
  220. package/dist/shared/workspace/stigmer-link.js +3 -3
  221. package/dist/shared/workspace/writeback-coordinator.d.ts +15 -22
  222. package/dist/shared/workspace/writeback-coordinator.js +16 -53
  223. package/dist/shared/workspace/writeback-coordinator.js.map +1 -1
  224. package/dist/tools/index.d.ts +1 -1
  225. package/dist/tools/index.js +1 -1
  226. package/package.json +4 -4
  227. package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +1 -0
  228. package/src/__test-utils__/execution-record-fixture.ts +18 -2
  229. package/src/__test-utils__/file-review-projection.ts +156 -0
  230. package/src/__test-utils__/git-workspace-fixture.ts +58 -0
  231. package/src/__test-utils__/harness-boot-order-child.ts +7 -2
  232. package/src/__test-utils__/harness-contract/contract.ts +33 -20
  233. package/src/__test-utils__/harness-contract/recording-sink.ts +11 -1
  234. package/src/__test-utils__/harness-contract/runtime-contract.ts +328 -10
  235. package/src/__test-utils__/harness-contract/scripted-adapter.ts +38 -6
  236. package/src/__test-utils__/harness-contract/types.ts +27 -3
  237. package/src/__test-utils__/hermetic-activity.ts +52 -14
  238. package/src/__test-utils__/model-registry-fixture.ts +32 -7
  239. package/src/__test-utils__/module-specifiers.ts +24 -0
  240. package/src/__test-utils__/turn-input-fixture.ts +2 -2
  241. package/src/__tests__/harness-boot-order.test.ts +9 -2
  242. package/src/activities/call-agent.ts +2 -2
  243. package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +47 -3
  244. package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +2 -48
  245. package/src/activities/execute-cursor/__tests__/approval-decisions-agree.test.ts +1 -1
  246. package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +6 -1
  247. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +52 -27
  248. package/src/activities/execute-cursor/__tests__/cas-observations.test.ts +25 -0
  249. package/src/activities/execute-cursor/__tests__/goldens/prompt.enhanced.everything.prompt.md +166 -0
  250. package/src/activities/execute-cursor/__tests__/goldens/prompt.enhanced.plan-mode.prompt.md +186 -0
  251. package/src/activities/execute-cursor/__tests__/goldens/prompt.hitl.recovery.prompt.md +191 -0
  252. package/src/activities/execute-cursor/__tests__/goldens/prompt.hitl.reinvocation.prompt.md +13 -0
  253. package/src/activities/execute-cursor/__tests__/goldens/prompt.resumed.prefixed.prompt.md +32 -0
  254. package/src/activities/execute-cursor/__tests__/goldens/prompt.resumed.raw.prompt.md +1 -0
  255. package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +1 -2
  256. package/src/activities/execute-cursor/__tests__/hermetic/goldens/sdk-error-at-create.status.json +4 -0
  257. package/src/activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts +24 -4
  258. package/src/activities/execute-cursor/__tests__/hermetic/stream-self-stop-arms.test.ts +6 -5
  259. package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +9 -0
  260. package/src/activities/execute-cursor/__tests__/hitl-resume-history.test.ts +11 -8
  261. package/src/activities/execute-cursor/__tests__/prompt-goldens.test.ts +229 -0
  262. package/src/activities/execute-cursor/__tests__/same-identity-reproposal.test.ts +3 -3
  263. package/src/activities/execute-cursor/__tests__/sequential-gate-resume.test.ts +2 -2
  264. package/src/activities/execute-cursor/__tests__/turn-boundary.test.ts +78 -234
  265. package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +1 -26
  266. package/src/activities/execute-cursor/adapter.ts +7 -5
  267. package/src/activities/execute-cursor/approval-policy.ts +5 -2
  268. package/src/activities/execute-cursor/approval-state.ts +16 -8
  269. package/src/activities/execute-cursor/cas-observations.ts +20 -2
  270. package/src/activities/execute-cursor/cursor-capabilities.ts +24 -5
  271. package/src/activities/execute-cursor/message-translator.ts +29 -41
  272. package/src/activities/execute-cursor/prompt-builder.ts +99 -157
  273. package/src/activities/execute-cursor/turn-boundary.ts +34 -140
  274. package/src/activities/execute-cursor/turn-settle.ts +37 -51
  275. package/src/activities/execute-cursor/turn-setup.ts +30 -70
  276. package/src/activities/execute-cursor/turn-stream.ts +8 -31
  277. package/src/activities/execute-cursor/turn.ts +5 -1
  278. package/src/activities/execute-deep-agent/__test-utils__/contract-subject.ts +391 -0
  279. package/src/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.ts +313 -0
  280. package/src/activities/execute-deep-agent/__test-utils__/hitl-script.ts +48 -0
  281. package/src/activities/execute-deep-agent/__test-utils__/scripted-model-module.ts +85 -0
  282. package/src/activities/execute-deep-agent/__test-utils__/scripted-model.ts +383 -36
  283. package/src/activities/execute-deep-agent/__tests__/adapter-graph-is-sdk-free.test.ts +76 -0
  284. package/src/activities/execute-deep-agent/__tests__/adapter-is-temporal-free.test.ts +47 -0
  285. package/src/activities/execute-deep-agent/__tests__/adapter.test.ts +80 -0
  286. package/src/activities/execute-deep-agent/__tests__/cas-capture-backend.test.ts +1 -1
  287. package/src/activities/execute-deep-agent/__tests__/execution-state-extended.test.ts +0 -2
  288. package/src/activities/execute-deep-agent/__tests__/execution-state.test.ts +0 -3
  289. package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.build-from-plan.prompt.md +172 -0
  290. package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.everything.prompt.md +167 -0
  291. package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.minimal.prompt.md +36 -0
  292. package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.plan-mode.prompt.md +178 -0
  293. package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.skills-below-threshold.prompt.md +158 -0
  294. package/src/activities/execute-deep-agent/__tests__/hermetic/file-review-capture.test.ts +210 -0
  295. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn1.status.json +74 -0
  296. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn2.status.json +104 -0
  297. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve.turn2.status.json +78 -0
  298. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/file-review-capture.status.json +138 -0
  299. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/gate.turn1.status.json +68 -0
  300. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn1.status.json +154 -0
  301. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn2.status.json +116 -0
  302. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.after-tool.status.json +69 -0
  303. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.mid-tool.status.json +67 -0
  304. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/plain-turn.status.json +47 -0
  305. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/platform-stop.status.json +68 -0
  306. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/recursion-limit.persisted.status.json +280 -0
  307. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/reject.turn2.status.json +77 -0
  308. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/resolution-error.status.json +18 -0
  309. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn2.status.json +99 -0
  310. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn3.status.json +109 -0
  311. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/skip.turn2.status.json +76 -0
  312. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/structured-output.text-fallback.status.json +51 -0
  313. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/structured-output.tier2.status.json +51 -0
  314. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/structured-output.tool-strategy.status.json +56 -0
  315. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sub-agent-delegation.status.json +90 -0
  316. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/tool-call.status.json +70 -0
  317. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/worker-shutdown.status.json +71 -0
  318. package/src/activities/execute-deep-agent/__tests__/hermetic/harness-contract.test.ts +144 -0
  319. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-approve-all-lease.test.ts +184 -0
  320. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-round-trips.test.ts +203 -0
  321. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-sequential-gates.test.ts +170 -0
  322. package/src/activities/execute-deep-agent/__tests__/hermetic/inline-artifact-across-gate.test.ts +175 -0
  323. package/src/activities/execute-deep-agent/__tests__/hermetic/pause-vs-shutdown.test.ts +206 -0
  324. package/src/activities/execute-deep-agent/__tests__/hermetic/plain-turn.test.ts +142 -0
  325. package/src/activities/execute-deep-agent/__tests__/hermetic/platform-stop.test.ts +126 -0
  326. package/src/activities/execute-deep-agent/__tests__/hermetic/recursion-limit.test.ts +139 -0
  327. package/src/activities/execute-deep-agent/__tests__/hermetic/resolution-error.test.ts +122 -0
  328. package/src/activities/execute-deep-agent/__tests__/hermetic/structured-output.test.ts +236 -0
  329. package/src/activities/execute-deep-agent/__tests__/hermetic/sub-agent-delegation.test.ts +161 -0
  330. package/src/activities/execute-deep-agent/__tests__/hermetic/tool-call.test.ts +157 -0
  331. package/src/activities/execute-deep-agent/__tests__/hermetic/workspace-lock-timeout.test.ts +152 -0
  332. package/src/activities/execute-deep-agent/__tests__/hitl.test.ts +50 -122
  333. package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +8 -6
  334. package/src/activities/execute-deep-agent/__tests__/plan-mode-path-normalization.test.ts +2 -2
  335. package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +35 -35
  336. package/src/activities/execute-deep-agent/__tests__/prompt-goldens.test.ts +247 -0
  337. package/src/activities/execute-deep-agent/__tests__/scripted-model.test.ts +329 -0
  338. package/src/activities/execute-deep-agent/__tests__/status-builder-shared.test.ts +1 -20
  339. package/src/activities/execute-deep-agent/__tests__/streaming-side-effects.test.ts +78 -0
  340. package/src/activities/execute-deep-agent/__tests__/subagent-gitignored-capture.test.ts +1 -1
  341. package/src/activities/execute-deep-agent/__tests__/subagent-plan-mode-permissions.test.ts +2 -2
  342. package/src/activities/execute-deep-agent/__tests__/subagent-tracker.test.ts +57 -31
  343. package/src/activities/execute-deep-agent/__tests__/subagent-transformer.test.ts +19 -79
  344. package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +15 -15
  345. package/src/activities/execute-deep-agent/__tests__/summarization-verification.test.ts +1 -1
  346. package/src/activities/execute-deep-agent/__tests__/turn-stream.test.ts +391 -0
  347. package/src/activities/execute-deep-agent/__tests__/v3-status-builder.test.ts +343 -38
  348. package/src/activities/execute-deep-agent/__tests__/vision-input.test.ts +5 -5
  349. package/src/activities/execute-deep-agent/adapter.ts +94 -0
  350. package/src/activities/execute-deep-agent/cas-capture-observer.ts +11 -0
  351. package/src/activities/execute-deep-agent/deep-agent-capabilities.ts +43 -0
  352. package/src/activities/execute-deep-agent/execution-state.ts +4 -13
  353. package/src/activities/execute-deep-agent/hitl.ts +100 -123
  354. package/src/activities/execute-deep-agent/prompt-builder.ts +141 -115
  355. package/src/activities/execute-deep-agent/status-builder-shared.ts +21 -84
  356. package/src/activities/execute-deep-agent/streaming-side-effects.ts +13 -19
  357. package/src/activities/execute-deep-agent/subagent-tracker.ts +77 -42
  358. package/src/activities/execute-deep-agent/subagent-transformer.ts +46 -105
  359. package/src/activities/execute-deep-agent/subagent-wiring.ts +5 -4
  360. package/src/activities/execute-deep-agent/turn-settle.ts +164 -0
  361. package/src/activities/execute-deep-agent/turn-setup.ts +541 -0
  362. package/src/activities/execute-deep-agent/turn-stream.ts +313 -0
  363. package/src/activities/execute-deep-agent/turn.ts +131 -0
  364. package/src/activities/execute-deep-agent/v3-event-recorder.ts +6 -5
  365. package/src/activities/execute-deep-agent/v3-events.ts +1 -1
  366. package/src/activities/execute-deep-agent/v3-status-builder.ts +84 -63
  367. package/src/harness/__tests__/approval-decisions.test.ts +116 -0
  368. package/src/harness/__tests__/capture.test.ts +268 -0
  369. package/src/harness/__tests__/mount-skills.test.ts +169 -0
  370. package/src/harness/__tests__/persist-chokepoint.test.ts +38 -2
  371. package/src/harness/__tests__/run-turn-deterministic.test.ts +94 -0
  372. package/src/harness/__tests__/run-turn.test.ts +39 -23
  373. package/src/harness/__tests__/turn-attachments-vision.test.ts +80 -0
  374. package/src/harness/__tests__/turn-context.test.ts +73 -26
  375. package/src/harness/approval-decisions.ts +104 -0
  376. package/src/harness/capabilities.ts +16 -5
  377. package/src/harness/capture.ts +301 -0
  378. package/src/harness/persist-chokepoint.ts +24 -4
  379. package/src/harness/run-turn.ts +120 -29
  380. package/src/harness/terminal-table.ts +61 -20
  381. package/src/harness/turn-context.ts +208 -111
  382. package/src/harness/types.ts +66 -12
  383. package/src/harness-adapters.ts +17 -9
  384. package/src/middleware/__tests__/approval-gate.test.ts +1 -1
  385. package/src/middleware/__tests__/cost-advisory.test.ts +113 -0
  386. package/src/middleware/approval-gate.ts +2 -2
  387. package/src/middleware/{cost-cap.ts → cost-advisory.ts} +40 -70
  388. package/src/middleware/index.ts +29 -29
  389. package/src/middleware/types.ts +3 -2
  390. package/src/runner-manager.ts +0 -8
  391. package/src/runner.ts +0 -8
  392. package/src/shared/__tests__/attachment-naming.test.ts +6 -19
  393. package/src/shared/__tests__/attachment-resolver.test.ts +158 -8
  394. package/src/shared/__tests__/attachment-zip.test.ts +236 -0
  395. package/src/shared/__tests__/bedrock-adapter.test.ts +1 -1
  396. package/src/shared/__tests__/blueprint-resolver.test.ts +43 -0
  397. package/src/shared/__tests__/cost-guard.test.ts +3 -3
  398. package/src/shared/__tests__/prompt-sections.test.ts +167 -0
  399. package/src/shared/__tests__/secret-leak-scan.test.ts +2 -2
  400. package/src/{activities/execute-deep-agent → shared}/__tests__/stamp-flowed-rows.test.ts +33 -10
  401. package/src/shared/__tests__/vertex-adapter.test.ts +1 -1
  402. package/src/shared/attachment-resolver.ts +218 -55
  403. package/src/shared/attachment-zip.ts +281 -0
  404. package/src/shared/connect-backfill.ts +9 -11
  405. package/src/shared/cost-guard.ts +3 -3
  406. package/src/shared/execution-status-writer.ts +5 -5
  407. package/src/shared/extract-structured-output.ts +8 -7
  408. package/src/shared/filereview/__tests__/capture.test.ts +86 -4
  409. package/src/shared/filereview/__tests__/cas-progress.test.ts +2 -1
  410. package/src/shared/filereview/cas-progress.ts +5 -19
  411. package/src/shared/filereview/cas-touched.ts +89 -0
  412. package/src/shared/filereview/index.ts +4 -2
  413. package/src/shared/mcp-resolver.ts +4 -5
  414. package/src/shared/persist-decision.ts +3 -4
  415. package/src/shared/plan-mode-permissions.ts +2 -2
  416. package/src/shared/plan-mode-prompt.ts +1 -1
  417. package/src/shared/prompt-sections.ts +256 -0
  418. package/src/shared/skill-resolver.ts +4 -2
  419. package/src/shared/tool-rounds.ts +48 -0
  420. package/src/shared/tool-row.ts +61 -0
  421. package/src/shared/workspace/__tests__/stigmer-link.test.ts +7 -22
  422. package/src/shared/workspace/__tests__/writeback-coordinator.test.ts +20 -61
  423. package/src/shared/workspace/session-provision.ts +3 -3
  424. package/src/shared/workspace/stigmer-link.ts +3 -3
  425. package/src/shared/workspace/writeback-coordinator.ts +16 -64
  426. package/src/tools/index.ts +1 -1
  427. package/dist/activities/execute-cursor/capture-flow.d.ts +0 -142
  428. package/dist/activities/execute-cursor/capture-flow.js +0 -285
  429. package/dist/activities/execute-cursor/capture-flow.js.map +0 -1
  430. package/dist/activities/execute-cursor/command-provenance.d.ts +0 -48
  431. package/dist/activities/execute-cursor/command-provenance.js +0 -38
  432. package/dist/activities/execute-cursor/command-provenance.js.map +0 -1
  433. package/dist/activities/execute-deep-agent/attachment-injector.d.ts +0 -134
  434. package/dist/activities/execute-deep-agent/attachment-injector.js +0 -386
  435. package/dist/activities/execute-deep-agent/attachment-injector.js.map +0 -1
  436. package/dist/activities/execute-deep-agent/command-provenance.d.ts +0 -61
  437. package/dist/activities/execute-deep-agent/command-provenance.js +0 -72
  438. package/dist/activities/execute-deep-agent/command-provenance.js.map +0 -1
  439. package/dist/activities/execute-deep-agent/environment.d.ts +0 -24
  440. package/dist/activities/execute-deep-agent/environment.js +0 -58
  441. package/dist/activities/execute-deep-agent/environment.js.map +0 -1
  442. package/dist/activities/execute-deep-agent/event-recorder.d.ts +0 -21
  443. package/dist/activities/execute-deep-agent/event-recorder.js +0 -67
  444. package/dist/activities/execute-deep-agent/event-recorder.js.map +0 -1
  445. package/dist/activities/execute-deep-agent/index.d.ts +0 -15
  446. package/dist/activities/execute-deep-agent/index.js +0 -918
  447. package/dist/activities/execute-deep-agent/index.js.map +0 -1
  448. package/dist/activities/execute-deep-agent/mcp-gate.d.ts +0 -28
  449. package/dist/activities/execute-deep-agent/mcp-gate.js +0 -22
  450. package/dist/activities/execute-deep-agent/mcp-gate.js.map +0 -1
  451. package/dist/activities/execute-deep-agent/post-stream.d.ts +0 -23
  452. package/dist/activities/execute-deep-agent/post-stream.js +0 -71
  453. package/dist/activities/execute-deep-agent/post-stream.js.map +0 -1
  454. package/dist/activities/execute-deep-agent/setup.d.ts +0 -136
  455. package/dist/activities/execute-deep-agent/setup.js +0 -767
  456. package/dist/activities/execute-deep-agent/setup.js.map +0 -1
  457. package/dist/activities/execute-deep-agent/stamp-flowed-rows.d.ts +0 -36
  458. package/dist/activities/execute-deep-agent/stamp-flowed-rows.js +0 -56
  459. package/dist/activities/execute-deep-agent/stamp-flowed-rows.js.map +0 -1
  460. package/dist/activities/execute-deep-agent/status-builder.d.ts +0 -93
  461. package/dist/activities/execute-deep-agent/status-builder.js +0 -365
  462. package/dist/activities/execute-deep-agent/status-builder.js.map +0 -1
  463. package/dist/activities/execute-deep-agent/streaming-terminal.d.ts +0 -21
  464. package/dist/activities/execute-deep-agent/streaming-terminal.js +0 -80
  465. package/dist/activities/execute-deep-agent/streaming-terminal.js.map +0 -1
  466. package/dist/activities/execute-deep-agent/streaming-v3.d.ts +0 -13
  467. package/dist/activities/execute-deep-agent/streaming-v3.js +0 -174
  468. package/dist/activities/execute-deep-agent/streaming-v3.js.map +0 -1
  469. package/dist/activities/execute-deep-agent/streaming.d.ts +0 -81
  470. package/dist/activities/execute-deep-agent/streaming.js +0 -160
  471. package/dist/activities/execute-deep-agent/streaming.js.map +0 -1
  472. package/dist/middleware/cost-cap.d.ts +0 -22
  473. package/dist/middleware/cost-cap.js.map +0 -1
  474. package/dist/middleware/graceful-stop.d.ts +0 -17
  475. package/dist/middleware/graceful-stop.js +0 -63
  476. package/dist/middleware/graceful-stop.js.map +0 -1
  477. package/dist/shared/skill-writer.d.ts +0 -75
  478. package/dist/shared/skill-writer.js +0 -207
  479. package/dist/shared/skill-writer.js.map +0 -1
  480. package/src/activities/execute-cursor/__tests__/capture-flow.test.ts +0 -1032
  481. package/src/activities/execute-cursor/__tests__/command-provenance.test.ts +0 -240
  482. package/src/activities/execute-cursor/__tests__/progress-substrate.test.ts +0 -169
  483. package/src/activities/execute-cursor/capture-flow.ts +0 -379
  484. package/src/activities/execute-cursor/command-provenance.ts +0 -73
  485. package/src/activities/execute-deep-agent/__tests__/attachment-injector.test.ts +0 -1161
  486. package/src/activities/execute-deep-agent/__tests__/command-provenance.test.ts +0 -252
  487. package/src/activities/execute-deep-agent/__tests__/environment.test.ts +0 -108
  488. package/src/activities/execute-deep-agent/__tests__/event-recorder.test.ts +0 -150
  489. package/src/activities/execute-deep-agent/__tests__/hitl-integration.test.ts +0 -226
  490. package/src/activities/execute-deep-agent/__tests__/hitl-reject.test.ts +0 -318
  491. package/src/activities/execute-deep-agent/__tests__/hitl-resume-approve-all.test.ts +0 -351
  492. package/src/activities/execute-deep-agent/__tests__/hitl-resume-history.test.ts +0 -293
  493. package/src/activities/execute-deep-agent/__tests__/index.test.ts +0 -99
  494. package/src/activities/execute-deep-agent/__tests__/mcp-gate.test.ts +0 -44
  495. package/src/activities/execute-deep-agent/__tests__/post-stream.test.ts +0 -112
  496. package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +0 -358
  497. package/src/activities/execute-deep-agent/__tests__/status-builder.test.ts +0 -1933
  498. package/src/activities/execute-deep-agent/__tests__/streaming-terminal.test.ts +0 -40
  499. package/src/activities/execute-deep-agent/__tests__/streaming-v3.test.ts +0 -597
  500. package/src/activities/execute-deep-agent/__tests__/streaming.test.ts +0 -508
  501. package/src/activities/execute-deep-agent/attachment-injector.ts +0 -627
  502. package/src/activities/execute-deep-agent/command-provenance.ts +0 -102
  503. package/src/activities/execute-deep-agent/environment.ts +0 -76
  504. package/src/activities/execute-deep-agent/event-recorder.ts +0 -95
  505. package/src/activities/execute-deep-agent/index.ts +0 -1072
  506. package/src/activities/execute-deep-agent/mcp-gate.ts +0 -37
  507. package/src/activities/execute-deep-agent/post-stream.ts +0 -109
  508. package/src/activities/execute-deep-agent/setup.ts +0 -1081
  509. package/src/activities/execute-deep-agent/stamp-flowed-rows.ts +0 -64
  510. package/src/activities/execute-deep-agent/status-builder.ts +0 -481
  511. package/src/activities/execute-deep-agent/streaming-terminal.ts +0 -106
  512. package/src/activities/execute-deep-agent/streaming-v3.ts +0 -277
  513. package/src/activities/execute-deep-agent/streaming.ts +0 -313
  514. package/src/middleware/__tests__/cost-cap.test.ts +0 -192
  515. package/src/middleware/__tests__/graceful-stop.test.ts +0 -105
  516. package/src/middleware/graceful-stop.ts +0 -86
  517. package/src/shared/__tests__/skill-writer.test.ts +0 -372
  518. package/src/shared/skill-writer.ts +0 -266
@@ -29,9 +29,12 @@
29
29
  * name->category mapping are baked into the generated hook script (from
30
30
  * approval-policy.ts), not carried in the state file — only the dynamic inputs
31
31
  * (autoApproveAll, leasedCategories, mcpToolPolicies, approvedGrantTokens) live
32
- * here. This mirrors the native harness and avoids denying auto-approved MCP
33
- * tools, which are absent from the policy map and indistinguishable from unknown
34
- * tools by name.
32
+ * here. The gated set is the shared taxonomy (`shared/tool-kind.ts`
33
+ * `toolApprovalCategory`, the native gate's too), and the policy map is the
34
+ * runtime's merged one (`TurnInput.mcp.policies`), so this file adds no rule of
35
+ * its own; fail-open on an unknown name is what keeps auto-approved MCP tools
36
+ * — absent from the policy map and indistinguishable from unknown tools by
37
+ * name — from being denied.
35
38
  *
36
39
  * Approval leases (the scoped successor to autoApproveAll): `autoApproveAll` is
37
40
  * now ONLY the pre-armed spec.auto_approve_all global bypass. An interactive
@@ -208,9 +211,10 @@ export interface ApprovalStateFile {
208
211
  * CAS capture for gitignored writes (the deep-agent parity switch). When true,
209
212
  * a non-secret gitignored write/edit no longer stays on the deny-gate: the hook
210
213
  * stages its pre-write bytes into the runner-owned cas-observations sidecar and
211
- * ALLOWS it to flow, and the turn boundary captures it into content-addressable
212
- * storage as a `GIT_IGNORED_CAPTURED` change for per-file review (mirroring the
213
- * deep-agent `CasCaptureFilesystemBackend` observer). A secret-like gitignored
214
+ * ALLOWS it to flow, and the runtime's capture (`harness/capture.ts`, reading
215
+ * the sidecar as this adapter's CAS observations) stores it as a
216
+ * `GIT_IGNORED_CAPTURED` change for per-file review (the deep-agent's
217
+ * `CasCaptureFilesystemBackend` observer is the same fact, in-process). A secret-like gitignored
214
218
  * path is instead hard-blocked (denied, nothing written) and recorded as an
215
219
  * unreviewable observation, so its bytes never reach durable storage.
216
220
  *
@@ -776,8 +780,12 @@ export async function removeActiveTurnPointer(gateDir: string): Promise<void> {
776
780
  * (PendingApprovalComputer) and CLEARS entries once they carry an approval_action,
777
781
  * so by the time the workflow reinvokes this activity, pending_approvals is empty
778
782
  * and the decision survives only on the tool call (status WAITING_APPROVAL +
779
- * approval_action set). This mirrors the native harness
780
- * (execute-deep-agent/hitl.ts extractApprovalDecisions).
783
+ * approval_action set). The runtime reads the same rows for the decisions
784
+ * themselves (`harness/approval-decisions.ts` `approvalDecisionsOf`, on
785
+ * `TurnInput.approvalDecisions`, for every harness); this reader exists for
786
+ * the two facts only this harness needs beside them — the pending-approval
787
+ * protos the grant and prompt builders take, and the content digests for the
788
+ * exact grant — and a test pins the two readers' agreement.
781
789
  *
782
790
  * Returns a PendingApproval list reconstructed from those tool calls (so the
783
791
  * existing grant/prompt builders work unchanged) alongside the decision map.
@@ -11,7 +11,9 @@
11
11
  * invocation is a FRESH, EPHEMERAL process that cannot hold in-memory state
12
12
  * across writes. So Cursor's before-map must be DISK-BACKED: the hook stages each
13
13
  * first-touched gitignored path into a per-turn "cas-observations" sidecar, and
14
- * the runner reads it back at the turn boundary.
14
+ * the runtime reads it back as the CAS observations this adapter binds on
15
+ * the sink ({@link readSidecarSnapshot}) — at each progress capture and at
16
+ * the turn boundary (`harness/capture.ts`).
15
17
  *
16
18
  * The sidecar lives under the session HITL directory
17
19
  * (`~/.stigmer/sessions/{id}/hitl/cas-observations/`), OUTSIDE the user's
@@ -22,7 +24,8 @@
22
24
  * never this scratch. A Temporal retry re-runs the reset and re-observes.
23
25
  *
24
26
  * ONE MODULE OWNS THE ON-DISK FORMAT. Both sides live here so they cannot drift:
25
- * - the READER ({@link readCasObservations}) the runner boundary calls;
27
+ * - the READER ({@link readCasObservations}, and its runtime-shaped view
28
+ * {@link readSidecarSnapshot});
26
29
  * - the WRITER-SCRIPT GENERATOR ({@link buildObservationStagingScript}) whose
27
30
  * output the hook embeds and runs on the runner's own Node binary. The writer
28
31
  * classifies secrets from the SAME {@link isSecretLikePath} pattern arrays the
@@ -43,6 +46,7 @@
43
46
 
44
47
  import { readFile, readdir, rm, mkdir } from "node:fs/promises";
45
48
  import { join } from "node:path";
49
+ import type { CasTouchedSnapshot } from "../../shared/filereview/cas-touched.js";
46
50
  import { SECRET_BASENAME_PATTERNS, SECRET_PATH_PATTERNS } from "../../shared/filereview/secret-paths.js";
47
51
 
48
52
  /** Sidecar directory name under the session HITL dir. */
@@ -135,6 +139,20 @@ export async function readCasObservations(hitlDir: string): Promise<CasObservati
135
139
  return { captured, secretPaths };
136
140
  }
137
141
 
142
+ /**
143
+ * One atomic read of the sidecar as the runtime's {@link CasTouchedSnapshot}
144
+ * — what this adapter binds through `TurnSink.bindCasObservations`. The
145
+ * sidecar is small (one marker plus one before-blob per touched path), so
146
+ * re-reading it per capture is cheap and always reflects a sub-agent's
147
+ * writes staged since the last read.
148
+ */
149
+ export async function readSidecarSnapshot(hitlDir: string): Promise<CasTouchedSnapshot> {
150
+ const { captured, secretPaths } = await readCasObservations(hitlDir);
151
+ const before = new Map<string, Uint8Array | null>();
152
+ for (const c of captured) before.set(c.path, c.before);
153
+ return { before, blockedSecretPaths: new Set(secretPaths) };
154
+ }
155
+
138
156
  /**
139
157
  * Emit a JS `RegExp` constructor byte-identical to a source pattern, safe to
140
158
  * embed inside a single-quoted bash string (JSON.stringify emits double quotes;
@@ -15,14 +15,33 @@
15
15
  * - No tool restriction in the SDK config: the hook's "disabled" arm
16
16
  * enforces `enabledTools` at call time (issue #350).
17
17
  * - PNG and JPEG inline; the transport re-sniffs (`shared/attachment-vision.ts`).
18
- * - File review under the `cursor` harness id, with the transient
19
- * `.cursor/hooks.json` the gate writes excluded from every diff
20
- * (`capture-flow.ts`).
18
+ * - File review under the `cursor` harness id, with the two files the gate
19
+ * writes into the repo excluded from the mid-run progress diff
20
+ * ({@link CURSOR_RUNNER_OWNED_PATHS}). The capture itself is the runtime's
21
+ * (`harness/capture.ts`, S3 M4); this adapter contributes only the hook
22
+ * sidecar it binds as the runtime's CAS observations (`turn-setup.ts`).
21
23
  */
22
24
 
23
- import type { HarnessCapabilities } from "../../harness/capabilities.js";
25
+ import type { FileReviewIdentity, HarnessCapabilities } from "../../harness/capabilities.js";
24
26
  import { CURSOR_VISION_PROFILE } from "../../shared/attachment-vision.js";
25
- import { CURSOR_FILE_REVIEW_IDENTITY } from "./capture-flow.js";
27
+
28
+ /**
29
+ * Workspace-relative paths the Cursor gate writes into the repo for the
30
+ * turn's duration (`workspace-setup.ts`). Excluded from the runtime's capture
31
+ * so a turn's diff never shows the gate's own machinery: at the boundary the
32
+ * gate is already torn down (the adapter's `finally` restores both), so the
33
+ * exclusion is load-bearing for the MID-RUN progress slice, which reads the
34
+ * tree while the gate is installed. The workspace-scoped gate dir and the
35
+ * SDK state live under `~/.stigmer` / the git-excluded `.stigmer`, so they
36
+ * need no exclusion.
37
+ */
38
+ const CURSOR_RUNNER_OWNED_PATHS: readonly string[] = [".cursor/hooks.json", ".cursor/rules/stigmer-tool-approval.mdc"];
39
+
40
+ /** The two facts the runtime's capture and reconcile read from this harness (`harness/capabilities.ts` `FileReviewIdentity`). */
41
+ export const CURSOR_FILE_REVIEW_IDENTITY: FileReviewIdentity = {
42
+ harnessId: "cursor",
43
+ excludePaths: CURSOR_RUNNER_OWNED_PATHS,
44
+ };
26
45
 
27
46
  export const CURSOR_CAPABILITIES: HarnessCapabilities = {
28
47
  pausePrimitive: "deny-and-retry",
@@ -30,13 +30,11 @@
30
30
  * - approvalMessage: from the policy, with placeholder resolution
31
31
  */
32
32
 
33
- import { clone, create } from "@bufbuild/protobuf";
33
+ import { create } from "@bufbuild/protobuf";
34
34
  import type { JsonObject } from "@bufbuild/protobuf";
35
- import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
36
35
  import { AgentMessageSchema, ToolCallSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
37
36
  import type { AgentMessage, ToolCall } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
38
- import { SubAgentExecutionSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/subagent_pb";
39
- import type { SubAgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/subagent_pb";
37
+ import { SubAgentExecutionSchema, type SubAgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/subagent_pb";
40
38
  import { ApprovalAction, ApprovalPolicySource, MessageType, ToolCallStatus, SubAgentStatus, ToolKind } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
41
39
  import type { SDKMessage } from "@cursor/sdk";
42
40
  import type { MergedToolPolicy } from "./approval-policy.js";
@@ -730,29 +728,15 @@ export interface MessageAccumulatorOptions {
730
728
  */
731
729
  workspaceRoot?: string;
732
730
  /**
733
- * Sub-agent executions carried over from the persisted transcript on a
734
- * durable resume ({@link seededSubAgentsOf}). The accumulator re-registers
735
- * them so a sub-agent's resumed lifecycle updates merge onto the seeded row
736
- * instead of producing a duplicate, and so the row survives the round-trip
737
- * rather than being dropped from the rebuilt status. Empty on a first run.
731
+ * The status's own `subAgentExecutions` array, wrapped BY REFERENCE exactly
732
+ * as `messages` is: the accumulator upserts into it in place, so the rows
733
+ * the runtime seeded on a resume (`harness/turn-context.ts`
734
+ * `seedFromPersistedStatus`) are indexed by id at construction and a
735
+ * resumed sub-agent's lifecycle updates merge onto its seeded row instead
736
+ * of producing a duplicate. Omitted in unit tests that only assert basic
737
+ * translation; the accumulator then owns a private array.
738
738
  */
739
- seededSubAgents?: readonly SubAgentExecution[];
740
- }
741
-
742
- /**
743
- * The sub-agent rows a resumed turn re-registers, cloned from the persisted
744
- * execution so the input stays immutable. This accumulator OWNS
745
- * `status.subAgentExecutions` and overwrites it on every flush, which is why
746
- * the runtime's transcript seeding (`harness/turn-context.ts`
747
- * `seedTranscriptFromExecution`) leaves the sub-agents to this harness: they
748
- * are re-registered here, never pushed onto the status. Same "left a
749
- * transcript" test as the seeding, so a resume that seeded messages always
750
- * seeds their sub-agents too.
751
- */
752
- export function seededSubAgentsOf(execution: AgentExecution): SubAgentExecution[] {
753
- const persisted = execution.status;
754
- if (!persisted || persisted.messages.length === 0) return [];
755
- return persisted.subAgentExecutions.map((sub) => clone(SubAgentExecutionSchema, sub));
739
+ subAgentExecutions?: SubAgentExecution[];
756
740
  }
757
741
 
758
742
  /**
@@ -787,7 +771,7 @@ export class MessageAccumulator {
787
771
  private readonly messages: AgentMessage[];
788
772
  private activeAiByRunId = new Map<string, AgentMessage>();
789
773
  private activeThinkingByRunId = new Map<string, AgentMessage>();
790
- private readonly _subAgentExecutions: SubAgentExecution[] = [];
774
+ private readonly _subAgentExecutions: SubAgentExecution[];
791
775
  private readonly subAgentMap = new Map<string, SubAgentExecution>();
792
776
  private readonly mergedPolicies?: ReadonlyMap<string, MergedToolPolicy>;
793
777
  private readonly provenance?: ApprovalProvenanceContext;
@@ -797,20 +781,23 @@ export class MessageAccumulator {
797
781
 
798
782
  constructor(messages: AgentMessage[], options?: MessageAccumulatorOptions) {
799
783
  this.messages = messages;
784
+ this._subAgentExecutions = options?.subAgentExecutions ?? [];
800
785
  this.mergedPolicies = options?.mergedPolicies;
801
786
  this.provenance = options?.provenance;
802
787
  this.workspaceRoot = options?.workspaceRoot;
803
788
 
804
- // Resume seeding. When constructed over a pre-seeded transcript (a durable
805
- // resume see seedCursorTranscriptFromExecution in index.ts), rebuild the
806
- // by-id tool-call index so a cross-message completion for a seeded call
807
- // resolves onto the existing proto, and re-register seeded sub-agents so
808
- // their resumed lifecycle updates merge in place. A first run carries an
809
- // empty transcript and no seed, so both are no-ops. Mirrors the deep-agent
810
- // ExecutionState.rebuildToolCallIndex + sub-agent re-registration on resume.
789
+ // Resume seeding. When constructed over a pre-seeded status (the runtime's
790
+ // `seedFromPersistedStatus` on a resume), rebuild the by-id indexes so a
791
+ // cross-message completion for a seeded call resolves onto the existing
792
+ // proto and a resumed sub-agent's lifecycle updates merge onto its seeded
793
+ // row. A first run carries an empty status, so both are no-ops.
811
794
  this.rebuildToolCallIndex();
812
- for (const sub of options?.seededSubAgents ?? []) {
813
- this._subAgentExecutions.push(sub);
795
+ this.rebuildSubAgentIndex();
796
+ }
797
+
798
+ /** Index every sub-agent row already present in the (seeded) array by its id, so upserts land on it. */
799
+ private rebuildSubAgentIndex(): void {
800
+ for (const sub of this._subAgentExecutions) {
814
801
  if (sub.id) this.subAgentMap.set(sub.id, sub);
815
802
  }
816
803
  }
@@ -936,10 +923,11 @@ export class MessageAccumulator {
936
923
  // grants already use — see toolCallIdentityToken) and keep the original id.
937
924
  // Without this the seeded approved call and the re-run would both appear (a
938
925
  // duplicate row) and dropping the seeded id would trip the backend's
939
- // append-only-at-identity guard, stalling the run. This generalizes the v2
940
- // deep-agent StatusBuilder.findResumableSeededToolCall (a tool-name match)
941
- // to the full Cursor identity, reusing the single existing identity
942
- // definition rather than introducing a parallel one.
926
+ // append-only-at-identity guard, stalling the run. This generalizes what
927
+ // the native builder does by exact tool_call_id (`V3StatusBuilder`'s resume
928
+ // reconciliation; its v2 predecessor matched by tool name) to the full
929
+ // Cursor identity, reusing the single existing identity definition rather
930
+ // than introducing a parallel one.
943
931
  const seeded = this.findResumableSeededToolCall(tc);
944
932
  if (seeded) {
945
933
  // Re-key the fresh call_id onto the seeded proto so this call_id's later
@@ -1170,7 +1158,7 @@ export class MessageAccumulator {
1170
1158
  * WAITING_APPROVAL.
1171
1159
  *
1172
1160
  * This is the cursor analog of the native harness synthesizing WAITING_APPROVAL
1173
- * tool calls from LangGraph interrupts (execute-deep-agent/index.ts). The hook
1161
+ * tool calls from LangGraph interrupts (execute-deep-agent/turn-settle.ts). The hook
1174
1162
  * ledger — not the SDK-reported tool status — is the authoritative record of
1175
1163
  * what was gated, because the hook is the only component that makes the per-call
1176
1164
  * allow/deny decision. The backend then projects pending_approvals from these
@@ -1,52 +1,53 @@
1
1
  /**
2
- * Builds the enhanced prompt for the Cursor agent.
2
+ * The Cursor harness's prompt: the four shapes `buildPrompt` selects from how
3
+ * the agent resolved and whether the turn carries adjudicated approvals
4
+ * (`capabilities.systemPrompt` is false — `@cursor/sdk` takes no system
5
+ * prompt, so the blueprint and the standing context ride the session's FIRST
6
+ * user message and persist in the agent's own conversation store; a resumed
7
+ * agent receives only what is per-turn).
3
8
  *
4
- * Replicates prompt_builder.py::enhance_system_prompt() but delivers
5
- * the content via the first user message (Cursor SDK has no systemPrompt
6
- * parameter). On reinvocation, only the approval decisions are sent.
9
+ * What is this harness's and what is shared (S3 M5, Q-S3-10 / Q-M5-2):
10
+ * - Shared through `shared/prompt-sections.ts`: WHICH standing sections
11
+ * render and in WHAT order (`standingContextSections`) and the input-files
12
+ * bullet and disclosure lines (`inputFileLines`). Their WORDS come from
13
+ * each fact's own module; this builder only frames them.
14
+ * - This harness's: the framing — `<xml_tag>` sections joined by `---`
15
+ * rules, the idiom for structured content inside a USER message — and the
16
+ * placement (which sections a first message carries, which a resumed
17
+ * turn's prefix repeats, where the catchup and the protocol sit); every
18
+ * text that quotes this engine: `<available_skills>` (`the Read tool`),
19
+ * `<sub_agent_delegation>` and `<codebase_exploration>` (the Task tool and
20
+ * the built-in `explore` agent), the response rules, the structured-output
21
+ * directive (prose JSON the activity extracts); and the tool-approval
22
+ * protocol, which exists because of this harness's deny-based gate (see
23
+ * `formatToolApprovalProtocol`) and would be false on an engine that
24
+ * interrupts before a tool runs.
7
25
  *
8
- * Sections (in order, conditionally included):
9
- * 1. Interaction-mode / implement-plan directives
10
- * 2. Agent instructions (persona/character)
11
- * 3. Available skills metadata
12
- * 4. Sub-agent delegation guidance
13
- * 5. Workspace context (multi-root only; single-dir is redundant with SDK cwd)
14
- * 6. Input files / referenced files
15
- * 7. Response rules (only when agent has no custom instructions)
16
- * 8. User's actual message
26
+ * The whole rendered prompt, per shape, is pinned by
27
+ * `__tests__/prompt-goldens.test.ts`; `__tests__/build-prompt.test.ts` pins
28
+ * every branch of the selection.
17
29
  */
18
30
 
19
31
  import { resolve } from "node:path";
20
32
  import type { SubAgent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
21
33
  import type { PendingApproval } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/approval_pb";
22
34
  import { ApprovalAction, InteractionMode } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
23
- import { formatContextBridgeText } from "../../shared/context-bridge.js";
24
35
  import { formatConversationCatchupText } from "../../shared/conversation-catchup.js";
25
36
  import {
26
37
  formatChannelTemplatesSection,
27
38
  type ChannelMessagingInfo,
28
39
  } from "../../shared/channel-attachment.js";
40
+ import type { SenderIdentity } from "../../shared/sender-identity.js";
41
+ import type { DeclaredPreferencesContent } from "../../shared/declared-preferences.js";
42
+ import type { RecalledMemoriesContent } from "../../shared/recalled-memories.js";
43
+ import type { DownloadUrlKind } from "../../shared/attachment-download-urls.js";
44
+ import type { ResolvedAttachment } from "../../shared/attachment-resolver.js";
29
45
  import {
30
- formatSenderIdentityText,
31
- type SenderIdentity,
32
- } from "../../shared/sender-identity.js";
33
- import { formatSessionContextText } from "../../shared/session-context.js";
34
- import {
35
- formatDeclaredPreferencesText,
36
- type DeclaredPreferencesContent,
37
- } from "../../shared/declared-preferences.js";
38
- import {
39
- formatRecalledMemoriesText,
40
- type RecalledMemoriesContent,
41
- } from "../../shared/recalled-memories.js";
42
- import {
43
- visionDisclosureLines,
44
- type NotViewableEntry,
45
- } from "../../shared/attachment-vision.js";
46
- import {
47
- downloadUrlDisclosureLine,
48
- type DownloadUrlKind,
49
- } from "../../shared/attachment-download-urls.js";
46
+ inputFileLines,
47
+ standingContextSections,
48
+ type StandingSectionKind,
49
+ type VisionPromptInfo,
50
+ } from "../../shared/prompt-sections.js";
50
51
  import { formatTurnRecoveryText } from "./turn-recovery.js";
51
52
  import type { SkillMetadata } from "../../shared/skill-resolver.js";
52
53
  import type { AgentResolution, AgentResolutionReason } from "./session-lifecycle.js";
@@ -68,34 +69,29 @@ const RUNNER_PATH_MARKERS = [
68
69
  "/dist/main.js",
69
70
  ] as const;
70
71
 
71
- /**
72
- * Vision facts about this turn's attachments, rendered inside the
73
- * input-files section: which images the model can see inline (in send
74
- * order) and which degraded to the file-pointer story. Derived per turn
75
- * from the resolved attachments never carried across turns.
76
- */
77
- export interface VisionPromptInfo {
78
- inlineFilenames: string[];
79
- notViewable: readonly NotViewableEntry[];
80
- }
72
+ // The prompt renders the attachment resolver's own result type — a local
73
+ // structural twin (`AttachmentPromptEntry`) lived here until S3 M5 and the
74
+ // projection into it was the one reason `turn-setup.ts` had a
75
+ // `prepareAttachmentPrompt` step; the twin dropped the size, so this
76
+ // harness's input-files line never carried it. One type, one truth: the
77
+ // runtime's `ResolvedAttachment`; the vision facts are the shared
78
+ // `VisionPromptInfo` (prompt-sections.ts) for the same reason.
79
+
80
+ export type { VisionPromptInfo };
81
81
 
82
82
  /**
83
- * One resolved attachment as the `<input_files>` section renders it —
84
- * the final workspace-relative path plus the duplicate-rename disclosure
85
- * (attachment-resolver.ts / shared/attachment-naming.ts).
83
+ * This harness's tag for each shared standing section (the section's
84
+ * identity and order are `prompt-sections.ts`'s; the XML framing is the
85
+ * idiom for structured content in a user message). Exhaustive by the
86
+ * compiler: a new kind fails here until it is named.
86
87
  */
87
- export interface AttachmentPromptEntry {
88
- /** Workspace-relative path the agent reads (`.stigmer/inputs/{filename}`). */
89
- path: string;
90
- /** Original filename, present only when a duplicate name was renamed. */
91
- renamedFrom?: string;
92
- /**
93
- * Download URL for the attachment's stored object, when one was minted
94
- * (shared/attachment-download-urls.ts) — rendered beside the path so the
95
- * agent can hand the file to tools that cannot read this filesystem.
96
- */
97
- downloadUrl?: string;
98
- }
88
+ const STANDING_SECTION_TAGS: Record<StandingSectionKind, string> = {
89
+ "conversation-sender": "conversation_sender",
90
+ "declared-preferences": "declared_preferences",
91
+ "recalled-memories": "recalled_memories",
92
+ "session-context": "session_context",
93
+ "previous-conversation": "previous_conversation_context",
94
+ };
99
95
 
100
96
  export interface EnhancedPromptOptions {
101
97
  instructions: string;
@@ -110,7 +106,8 @@ export interface EnhancedPromptOptions {
110
106
  subAgents: SubAgent[];
111
107
  workspaceDirs: string[];
112
108
  workspaceFileRefs: string[];
113
- attachments: AttachmentPromptEntry[];
109
+ /** This turn's resolved input files, as the runtime's attachment phase returns them. */
110
+ attachments: readonly ResolvedAttachment[];
114
111
  /** Inline/degraded image facts for the input-files section (T04 vision). */
115
112
  vision?: VisionPromptInfo;
116
113
  /**
@@ -248,41 +245,16 @@ export function buildEnhancedPrompt(options: EnhancedPromptOptions): string {
248
245
  sections.push(formatResponseRules());
249
246
  }
250
247
 
251
- // The sender identity precedes the bridge: it is standing context about
252
- // WHO the conversation is with, which the carried conversation may refer
253
- // back to.
254
- if (options.senderIdentity) {
255
- sections.push(formatSenderIdentitySection(options.senderIdentity));
256
- }
257
-
258
- // Platform-declared standing facts precede embedder-supplied context
259
- // (DD-002 D3): both are standing background, but the declared preferences
260
- // are platform-authored while session context is the embedder's overlay —
261
- // the more specific overlay reads later and naturally refines.
262
- if (options.declaredPreferences) {
263
- sections.push(formatDeclaredPreferencesSection(options.declaredPreferences));
264
- }
265
-
266
- // Declared-by-humans precedes learned-and-confirmed (DD-006 D4): both
267
- // are platform-authored standing background, but a preference is the
268
- // user's exact words while a memory is an agent's confirmed inference —
269
- // the exact statement reads first.
270
- if (options.recalledMemories) {
271
- sections.push(formatRecalledMemoriesSection(options.recalledMemories));
272
- }
273
-
274
- // Standing facts about the user (session context) come before the
275
- // carried conversation (bridge): the bridge may refer back to them.
276
- if (options.sessionContext) {
277
- sections.push(formatSessionContextSection(options.sessionContext));
278
- }
279
-
280
- // The rollover context bridge sits directly before the protocol + task so
281
- // the carried conversation is the freshest CONTEXT the model reads —
282
- // while the approval protocol keeps its pinned last-before-task slot (it
283
- // is an INSTRUCTION and must outweigh everything, including this bridge).
284
- if (options.contextBridge) {
285
- sections.push(formatContextBridgeSection(options.contextBridge));
248
+ // The standing context, in the shared order (the doctrine is stated once,
249
+ // on `standingContextSections`); this harness only frames each section.
250
+ // The block sits directly before the catchup, the protocol and the task so
251
+ // the carried conversation (its last section, the bridge) is the freshest
252
+ // CONTEXT the model reads — while the approval protocol keeps its pinned
253
+ // last-before-task slot (it is an INSTRUCTION and must outweigh
254
+ // everything, including the bridge).
255
+ for (const section of standingContextSections(options)) {
256
+ const tag = STANDING_SECTION_TAGS[section.kind];
257
+ sections.push(`<${tag}>\n${section.body}\n</${tag}>`);
286
258
  }
287
259
 
288
260
  // Catchup after the bridge (DD-007 D-d: bridge first, catchup second) —
@@ -328,6 +300,7 @@ export function buildReinvocationPrompt(
328
300
  const approved: string[] = [];
329
301
  const alreadyApplied: string[] = [];
330
302
  const skipped: string[] = [];
303
+ const rejected: string[] = [];
331
304
 
332
305
  for (const pa of pendingApprovals) {
333
306
  const action = approvalDecisions.get(pa.toolCallId);
@@ -339,6 +312,11 @@ export function buildReinvocationPrompt(
339
312
  approved.push(describeApproval(pa));
340
313
  } else if (action === ApprovalAction.SKIP) {
341
314
  skipped.push(describeApproval(pa));
315
+ } else if (action === ApprovalAction.REJECT) {
316
+ // A REJECT denies the tool and the run continues (stigmer#197); the
317
+ // runtime settles its row SKIPPED. Told apart from a SKIP in the prose
318
+ // so the model reads a refusal, not an omission (S3 M1, Q-S3-2).
319
+ rejected.push(describeApproval(pa));
342
320
  }
343
321
  }
344
322
 
@@ -366,6 +344,13 @@ export function buildReinvocationPrompt(
366
344
  skipped.map((a) => `- ${a}`).join("\n"),
367
345
  );
368
346
  }
347
+ if (rejected.length) {
348
+ parts.push(
349
+ "The user REJECTED the following action(s). Do not perform them; continue " +
350
+ "with the rest of the task without them:\n" +
351
+ rejected.map((a) => `- ${a}`).join("\n"),
352
+ );
353
+ }
369
354
 
370
355
  // The model's "ask the user first" bias recurs every turn, including resumes,
371
356
  // so restate the protocol: keep invoking tools directly to finish the task —
@@ -476,30 +461,10 @@ export function formatInstructions(instructions: string): string {
476
461
  return `<agent_instructions>\n${instructions}\n</agent_instructions>`;
477
462
  }
478
463
 
479
- export function formatContextBridgeSection(bridge: string): string {
480
- return `<previous_conversation_context>\n${formatContextBridgeText(bridge)}\n</previous_conversation_context>`;
481
- }
482
-
483
- export function formatSenderIdentitySection(identity: SenderIdentity): string {
484
- return `<conversation_sender>\n${formatSenderIdentityText(identity)}\n</conversation_sender>`;
485
- }
486
-
487
- export function formatDeclaredPreferencesSection(
488
- preferences: DeclaredPreferencesContent,
489
- ): string {
490
- return `<declared_preferences>\n${formatDeclaredPreferencesText(preferences)}\n</declared_preferences>`;
491
- }
492
-
493
- export function formatRecalledMemoriesSection(
494
- memories: RecalledMemoriesContent,
495
- ): string {
496
- return `<recalled_memories>\n${formatRecalledMemoriesText(memories)}\n</recalled_memories>`;
497
- }
498
-
499
- export function formatSessionContextSection(context: string): string {
500
- return `<session_context>\n${formatSessionContextText(context)}\n</session_context>`;
501
- }
502
-
464
+ /**
465
+ * The catchup is per-turn, not standing (it rides BOTH prompt paths), so it
466
+ * is framed here rather than through the shared standing block.
467
+ */
503
468
  export function formatConversationCatchupSection(digest: string): string {
504
469
  return `<conversation_catchup>\n${formatConversationCatchupText(digest)}\n</conversation_catchup>`;
505
470
  }
@@ -598,44 +563,24 @@ export function formatWorkspaceContext(dirs: string[]): string {
598
563
  ].join("\n");
599
564
  }
600
565
 
566
+ /**
567
+ * The `<input_files>` section: this harness's intro around the shared lines
568
+ * (`prompt-sections.ts` `inputFileLines` says what each bullet and disclosure
569
+ * carries and why). The size on each bullet is new to this harness at S3 M5
570
+ * (Q-M5-3): the twin this builder rendered from had dropped it.
571
+ */
601
572
  export function formatInputFiles(
602
- attachments: readonly AttachmentPromptEntry[],
573
+ attachments: readonly ResolvedAttachment[],
603
574
  vision?: VisionPromptInfo,
604
575
  downloadUrlKind?: DownloadUrlKind,
605
576
  ): string {
606
- // A duplicate-renamed file (attachment-naming.ts) discloses its original
607
- // name so the agent can connect "the two report.pdfs" in the user's
608
- // message to distinct files on disk. A file with a minted download URL
609
- // (attachment-download-urls.ts) lists it beside the path for the remote
610
- // hand-off story.
611
- const entries = attachments.map((a) => {
612
- const rename =
613
- a.renamedFrom !== undefined
614
- ? ` (renamed from duplicate '${a.renamedFrom}')`
615
- : "";
616
- const url = a.downloadUrl !== undefined ? ` — download URL: ${a.downloadUrl}` : "";
617
- return `- \`${a.path}\`${rename}${url}`;
618
- });
619
- // The URL hand-off line (shared wording, attachment-download-urls.ts)
620
- // renders only when some listed file actually carries a URL — its wording
621
- // keys on what kind of URL the storage backend mints.
622
- const urlDisclosure =
623
- downloadUrlKind !== undefined && attachments.some((a) => a.downloadUrl !== undefined)
624
- ? [downloadUrlDisclosureLine(downloadUrlKind)]
625
- : [];
626
- // The vision lines (shared wording, attachment-vision.ts) tell the model
627
- // which of these files it can already SEE inline versus which degraded to
628
- // path-only — without them an agent silently ignores a photo the user
629
- // believes it can see.
630
- const disclosure = vision
631
- ? visionDisclosureLines(vision.inlineFilenames, vision.notViewable)
632
- : [];
577
+ const lines = inputFileLines(attachments, vision, downloadUrlKind);
633
578
  return [
634
579
  "<input_files>",
635
580
  "The following files have been provided as inputs. Read them when relevant to the task:",
636
- ...entries,
637
- ...urlDisclosure,
638
- ...disclosure,
581
+ ...lines.entries,
582
+ ...(lines.urlHandoff !== undefined ? [lines.urlHandoff] : []),
583
+ ...lines.vision,
639
584
  "</input_files>",
640
585
  ].join("\n");
641
586
  }
@@ -684,14 +629,14 @@ export function formatInteractionModePrefix(
684
629
  */
685
630
  export function formatImplementPlanSection(
686
631
  buildFromPlan: boolean | undefined,
687
- attachments: readonly AttachmentPromptEntry[],
632
+ attachments: readonly ResolvedAttachment[],
688
633
  ): string | undefined {
689
634
  if (!buildFromPlan) {
690
635
  return undefined;
691
636
  }
692
637
 
693
638
  const directive = buildImplementPlanDirective(
694
- findApprovedPlanPath(attachments.map((a) => a.path)),
639
+ findApprovedPlanPath(attachments.map((a) => a.relativePath)),
695
640
  );
696
641
  return ["<implement_plan>", directive, "</implement_plan>"].join("\n");
697
642
  }
@@ -829,11 +774,8 @@ export interface BuildPromptInput {
829
774
  subAgents: SubAgent[];
830
775
  workspaceDirs: string[];
831
776
  workspaceFileRefs: string[];
832
- /**
833
- * This turn's resolved attachments for the `<input_files>` section —
834
- * final paths plus duplicate-rename disclosure (attachment-resolver.ts).
835
- */
836
- attachments: AttachmentPromptEntry[];
777
+ /** This turn's resolved input files for the `<input_files>` section, as the runtime's attachment phase returns them. */
778
+ attachments: readonly ResolvedAttachment[];
837
779
  /**
838
780
  * Vision facts for the input-files section (T04): which attachments the
839
781
  * model sees inline and which degraded to path-only. PER-TURN like the