@deksden-com/dd-flow-cli 0.9.0-beta.16 → 0.9.0-beta.160

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 (670) hide show
  1. package/CHANGELOG.md +959 -0
  2. package/README.md +139 -10
  3. package/dist/build-info.json +8 -8
  4. package/dist/cli/argument-values.js +38 -0
  5. package/dist/cli/command-inputs.js +417 -0
  6. package/dist/cli/command-metadata.js +303 -0
  7. package/dist/cli/command-option-descriptions.js +192 -0
  8. package/dist/cli/completion-cli.js +70 -0
  9. package/dist/cli/completion.js +57 -0
  10. package/dist/cli/delivery.js +108 -0
  11. package/dist/cli/diagnostic-invocation.js +62 -0
  12. package/dist/cli/diagnostic.js +131 -0
  13. package/dist/cli/error-output.js +62 -0
  14. package/dist/cli/executor-onboarding.js +76 -0
  15. package/dist/cli/flows.js +29 -0
  16. package/dist/cli/harnesses.js +84 -0
  17. package/dist/cli/help.js +521 -19
  18. package/dist/cli/hook-ingress.js +89 -0
  19. package/dist/cli/input-preparation.js +193 -0
  20. package/dist/cli/interactive-invocation.js +33 -0
  21. package/dist/cli/interactive.js +114 -0
  22. package/dist/cli/memory-fix-invocation.js +52 -0
  23. package/dist/cli/memory-fix.js +100 -0
  24. package/dist/cli/memory-flow-admission.js +54 -0
  25. package/dist/cli/memory-init-invocation.js +85 -0
  26. package/dist/cli/memory-init.js +250 -0
  27. package/dist/cli/memory-storage-admission.js +54 -0
  28. package/dist/cli/memory-storage-qualification.js +105 -0
  29. package/dist/cli/memory-storage-transition.js +123 -0
  30. package/dist/cli/memory-upgrade.js +189 -0
  31. package/dist/cli/models.js +39 -0
  32. package/dist/cli/native-hook-ingress.js +94 -0
  33. package/dist/cli/native-hook-preparation.js +82 -0
  34. package/dist/cli/operator-profiles.js +61 -0
  35. package/dist/cli/output-options.js +35 -0
  36. package/dist/cli/response-file.js +72 -0
  37. package/dist/cli/run-cli.js +2020 -555
  38. package/dist/cli/runtime-maintenance-diagnostics.js +46 -0
  39. package/dist/cli/runtime-maintenance-ingress.js +52 -0
  40. package/dist/cli/runtime-process.js +153 -0
  41. package/dist/cli/setup.js +150 -0
  42. package/dist/cli.js +103 -2
  43. package/dist/domain/delivery-flows.js +8 -0
  44. package/dist/domain/diagnostic-aspects.js +103 -0
  45. package/dist/domain/diagnostic-flows.js +8 -0
  46. package/dist/domain/distill-flow.js +20 -0
  47. package/dist/domain/interactive-flow.js +1 -0
  48. package/dist/domain/memory-fix-flow.js +2 -0
  49. package/dist/domain/review-fix-flow.js +2 -0
  50. package/dist/domain/source-snapshot-flows.js +4 -0
  51. package/dist/domain/stage-catalog.js +1 -1
  52. package/dist/domain/stage-handler-identities.js +28 -0
  53. package/dist/harness-runtime/DD-ZCODE.md +112 -0
  54. package/dist/harness-runtime/OPENCODE-LICENSE.txt +24 -0
  55. package/dist/harness-runtime/bin/dd-agy.mjs +71 -0
  56. package/dist/harness-runtime/bin/dd-codex.mjs +27 -0
  57. package/dist/harness-runtime/bin/dd-droid.mjs +34 -0
  58. package/dist/harness-runtime/bin/dd-grok.mjs +50 -0
  59. package/dist/harness-runtime/bin/dd-opencode.mjs +22 -0
  60. package/dist/harness-runtime/bin/dd-zcode.mjs +95 -0
  61. package/dist/harness-runtime/lib/adapter-timeouts.d.mts +5 -0
  62. package/dist/harness-runtime/lib/adapter-timeouts.mjs +34 -0
  63. package/dist/harness-runtime/lib/agy-error-boundary.mjs +87 -0
  64. package/dist/harness-runtime/lib/agy-hooks.d.mts +1 -0
  65. package/dist/harness-runtime/lib/agy-hooks.mjs +9 -0
  66. package/dist/harness-runtime/lib/agy-native-inspection.mjs +225 -0
  67. package/dist/harness-runtime/lib/agy-native-inventory.mjs +19 -0
  68. package/dist/harness-runtime/lib/agy-native_pb.js +117 -0
  69. package/dist/harness-runtime/lib/agy-terminal-envelope.mjs +74 -0
  70. package/dist/harness-runtime/lib/agy-transcript-stream.mjs +54 -0
  71. package/dist/harness-runtime/lib/daemon-observation.d.mts +3 -0
  72. package/dist/harness-runtime/lib/daemon-observation.mjs +171 -0
  73. package/dist/harness-runtime/lib/daemon-operations.d.mts +2 -0
  74. package/dist/harness-runtime/lib/daemon-operations.mjs +512 -0
  75. package/dist/harness-runtime/lib/dd-agy-daemon.d.mts +7 -0
  76. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +1362 -0
  77. package/dist/harness-runtime/lib/dd-agy.mjs +105 -0
  78. package/dist/harness-runtime/lib/dd-codex-daemon.d.mts +1 -0
  79. package/dist/harness-runtime/lib/dd-codex-daemon.mjs +271 -0
  80. package/dist/harness-runtime/lib/dd-codex.d.mts +1 -0
  81. package/dist/harness-runtime/lib/dd-codex.mjs +986 -0
  82. package/dist/harness-runtime/lib/dd-droid-daemon.mjs +155 -0
  83. package/dist/harness-runtime/lib/dd-droid.mjs +739 -0
  84. package/dist/harness-runtime/lib/dd-grok-daemon.d.mts +1 -0
  85. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +667 -0
  86. package/dist/harness-runtime/lib/dd-grok.mjs +182 -0
  87. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +772 -0
  88. package/dist/harness-runtime/lib/dd-opencode.mjs +411 -0
  89. package/dist/harness-runtime/lib/dd-zcode-daemon.d.mts +1 -0
  90. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +845 -0
  91. package/dist/harness-runtime/lib/dd-zcode.mjs +1239 -0
  92. package/dist/harness-runtime/lib/delegation-instructions.d.mts +16 -0
  93. package/dist/harness-runtime/lib/delegation-instructions.mjs +179 -0
  94. package/dist/harness-runtime/lib/delivery-command.mjs +84 -0
  95. package/dist/harness-runtime/lib/dispatch-fence.mjs +14 -0
  96. package/dist/harness-runtime/lib/driver-recovery.mjs +121 -0
  97. package/dist/harness-runtime/lib/droid-observation.mjs +70 -0
  98. package/dist/harness-runtime/lib/entity-references.d.mts +2 -0
  99. package/dist/harness-runtime/lib/entity-references.mjs +9 -0
  100. package/dist/harness-runtime/lib/lease-renewal.d.mts +8 -0
  101. package/dist/harness-runtime/lib/lease-renewal.mjs +37 -0
  102. package/dist/harness-runtime/lib/lifecycle-command.d.mts +20 -0
  103. package/dist/harness-runtime/lib/lifecycle-command.mjs +273 -0
  104. package/dist/harness-runtime/lib/lifecycle-contract.d.mts +11 -0
  105. package/dist/harness-runtime/lib/lifecycle-contract.mjs +20 -0
  106. package/dist/harness-runtime/lib/managed-daemon.d.mts +16 -0
  107. package/dist/harness-runtime/lib/managed-daemon.mjs +698 -0
  108. package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
  109. package/dist/harness-runtime/lib/model-observations.mjs +113 -0
  110. package/dist/harness-runtime/lib/native-children.d.mts +34 -0
  111. package/dist/harness-runtime/lib/native-children.mjs +265 -0
  112. package/dist/harness-runtime/lib/native-hook-command.d.mts +8 -0
  113. package/dist/harness-runtime/lib/native-hook-command.mjs +306 -0
  114. package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
  115. package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
  116. package/dist/harness-runtime/lib/native-streams.mjs +38 -0
  117. package/dist/harness-runtime/lib/observation-clock.d.mts +18 -0
  118. package/dist/harness-runtime/lib/observation-clock.mjs +95 -0
  119. package/dist/harness-runtime/lib/opencode-plugin.mjs +112 -0
  120. package/dist/harness-runtime/lib/operation-context.mjs +5 -0
  121. package/dist/harness-runtime/lib/operation-errors.d.mts +16 -0
  122. package/dist/harness-runtime/lib/operation-errors.mjs +140 -0
  123. package/dist/harness-runtime/lib/operation-progress.d.mts +7 -0
  124. package/dist/harness-runtime/lib/operation-progress.mjs +118 -0
  125. package/dist/harness-runtime/lib/process-json.d.mts +5 -0
  126. package/dist/harness-runtime/lib/process-json.mjs +200 -0
  127. package/dist/harness-runtime/lib/process-snapshot.mjs +10 -0
  128. package/dist/harness-runtime/lib/provider-overload-policy.d.mts +23 -0
  129. package/dist/harness-runtime/lib/provider-overload-policy.mjs +242 -0
  130. package/dist/harness-runtime/lib/runner-events.mjs +202 -0
  131. package/dist/harness-runtime/lib/runner-lock.mjs +42 -0
  132. package/dist/harness-runtime/lib/session-settlement.mjs +30 -0
  133. package/dist/harness-runtime/lib/setup-progress.d.mts +9 -0
  134. package/dist/harness-runtime/lib/setup-progress.mjs +53 -0
  135. package/dist/harness-runtime/lib/tool-observations.d.mts +21 -0
  136. package/dist/harness-runtime/lib/tool-observations.mjs +238 -0
  137. package/dist/harness-runtime/lib/zcode-native-hook-ownership.mjs +109 -0
  138. package/dist/harness-runtime/lib/zcode-usage.mjs +55 -0
  139. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-1y4a697q.js +81 -0
  140. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-2ny4vxct.js +92 -0
  141. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-6mptkzbc.js +0 -0
  142. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-7x67cf1q.js +52 -0
  143. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9rqn6x4v.js +16 -0
  144. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9vdz0zwn.js +1661 -0
  145. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ecs5ftka.js +1466 -0
  146. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-frbwqjmf.js +145 -0
  147. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gne7h7mq.js +50 -0
  148. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gx9wnkzr.js +105 -0
  149. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-m2eywc8w.js +0 -0
  150. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-nwcpakzx.js +12 -0
  151. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-q4g3afnw.js +623 -0
  152. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-qav6mfdz.js +0 -0
  153. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-sxt88q69.js +12 -0
  154. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-t1xa31vm.js +39 -0
  155. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ve4aws36.js +103 -0
  156. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vmytr4q8.js +4 -0
  157. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vt9jbch8.js +36 -0
  158. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vyas3vgt.js +0 -0
  159. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-wjyeq25y.js +30 -0
  160. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-xgnj2w4v.js +20 -0
  161. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-y2etg5bs.js +9 -0
  162. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ydhz1zrh.js +238 -0
  163. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-z6qdwcsf.js +62 -0
  164. package/dist/harness-runtime/vendor/opencode-client/contract.d.ts +1 -0
  165. package/dist/harness-runtime/vendor/opencode-client/contract.js +12 -0
  166. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.d.ts +2806 -0
  167. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.js +0 -0
  168. package/dist/harness-runtime/vendor/opencode-client/effect/api.d.ts +4 -0
  169. package/dist/harness-runtime/vendor/opencode-client/effect/api.js +0 -0
  170. package/dist/harness-runtime/vendor/opencode-client/effect/client.d.ts +2530 -0
  171. package/dist/harness-runtime/vendor/opencode-client/effect/client.js +15 -0
  172. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.d.ts +7 -0
  173. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.js +6 -0
  174. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.d.ts +2529 -0
  175. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.js +8 -0
  176. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.d.ts +2 -0
  177. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.js +12 -0
  178. package/dist/harness-runtime/vendor/opencode-client/effect/index.d.ts +35 -0
  179. package/dist/harness-runtime/vendor/opencode-client/effect/index.js +75 -0
  180. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.d.ts +20 -0
  181. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.js +11 -0
  182. package/dist/harness-runtime/vendor/opencode-client/effect/service.d.ts +90 -0
  183. package/dist/harness-runtime/vendor/opencode-client/effect/service.js +187 -0
  184. package/dist/harness-runtime/vendor/opencode-client/package.json +84 -0
  185. package/dist/harness-runtime/vendor/opencode-client/promise/api.d.ts +21 -0
  186. package/dist/harness-runtime/vendor/opencode-client/promise/api.js +0 -0
  187. package/dist/harness-runtime/vendor/opencode-client/promise/client.d.ts +252 -0
  188. package/dist/harness-runtime/vendor/opencode-client/promise/client.js +14 -0
  189. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.d.ts +8 -0
  190. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.js +6 -0
  191. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.d.ts +259 -0
  192. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.js +7 -0
  193. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.d.ts +3 -0
  194. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.js +79 -0
  195. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.d.ts +8932 -0
  196. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.js +70 -0
  197. package/dist/harness-runtime/vendor/opencode-client/promise/index.d.ts +6 -0
  198. package/dist/harness-runtime/vendor/opencode-client/promise/index.js +83 -0
  199. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.d.ts +32 -0
  200. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.js +7 -0
  201. package/dist/harness-runtime/vendor/opencode-client/promise/service.d.ts +24 -0
  202. package/dist/harness-runtime/vendor/opencode-client/promise/service.js +187 -0
  203. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.d.ts +12 -0
  204. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.js +14 -0
  205. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.d.ts +20 -0
  206. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.js +14 -0
  207. package/dist/harness-runtime/vendor/opencode-client/service-contender.d.ts +37 -0
  208. package/dist/harness-runtime/vendor/opencode-client/service-contender.js +10 -0
  209. package/dist/harness-runtime/vendor/opencode-client/service-probe.d.ts +70 -0
  210. package/dist/harness-runtime/vendor/opencode-client/service-probe.js +16 -0
  211. package/dist/harness-runtime/vendor/opencode-client/service-timing.d.ts +12 -0
  212. package/dist/harness-runtime/vendor/opencode-client/service-timing.js +10 -0
  213. package/dist/harness-runtime/vendor/opencode-client/service-version.d.ts +2 -0
  214. package/dist/harness-runtime/vendor/opencode-client/service-version.js +6 -0
  215. package/dist/harness-runtime/vendor/opencode-client/service.d.ts +52 -0
  216. package/dist/harness-runtime/vendor/opencode-client/service.js +1 -0
  217. package/dist/harness-runtime/vendor/opencode-client/shared-events.d.ts +11 -0
  218. package/dist/harness-runtime/vendor/opencode-client/shared-events.js +8 -0
  219. package/dist/harness-runtime/vendor/opencode-client/solid/connection.d.ts +37 -0
  220. package/dist/harness-runtime/vendor/opencode-client/solid/connection.js +10 -0
  221. package/dist/harness-runtime/vendor/opencode-client/solid/data.d.ts +211 -0
  222. package/dist/harness-runtime/vendor/opencode-client/solid/data.js +18 -0
  223. package/dist/harness-runtime/vendor/opencode-client/solid/index.d.ts +3 -0
  224. package/dist/harness-runtime/vendor/opencode-client/solid/index.js +32 -0
  225. package/dist/harness-runtime/vendor/opencode-client/solid/pty.d.ts +22 -0
  226. package/dist/harness-runtime/vendor/opencode-client/solid/pty.js +8 -0
  227. package/dist/harness-runtime/vendor/opencode-plugin.mjs +3 -0
  228. package/dist/protocol/local-files.js +18 -9
  229. package/dist/runtime/context.js +8 -4
  230. package/dist/schemas/agent-profile.schema.json +1 -1
  231. package/dist/schemas/code-review-decision.schema.json +9 -0
  232. package/dist/schemas/code-review-result.schema.json +1 -1
  233. package/dist/schemas/code-verification.schema.json +7 -5
  234. package/dist/schemas/code-work-batch.schema.json +2 -2
  235. package/dist/schemas/code-work-result.schema.json +2 -1
  236. package/dist/schemas/delivery-stage-result.schema.json +286 -0
  237. package/dist/schemas/diagnostic-stage-result.schema.json +354 -0
  238. package/dist/schemas/diagnostic-work-result.schema.json +296 -0
  239. package/dist/schemas/discovery-result.schema.json +184 -0
  240. package/dist/schemas/distill-stage-result.schema.json +667 -0
  241. package/dist/schemas/distill-work-result.schema.json +428 -0
  242. package/dist/schemas/execution-bundle.schema.json +215 -0
  243. package/dist/schemas/execution-settings.schema.json +162 -0
  244. package/dist/schemas/flow-descriptor.schema.json +54 -0
  245. package/dist/schemas/flow-run.schema.json +29 -0
  246. package/dist/schemas/harness-catalog.schema.json +80 -0
  247. package/dist/schemas/interactive-stage-result.schema.json +47 -0
  248. package/dist/schemas/interactive-work-result.schema.json +63 -0
  249. package/dist/schemas/mb-fix-stage-result.schema.json +93 -0
  250. package/dist/schemas/mb-init-compose-result.schema.json +457 -0
  251. package/dist/schemas/mb-init-discover-result.schema.json +500 -0
  252. package/dist/schemas/mb-init-finish-result.schema.json +422 -0
  253. package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
  254. package/dist/schemas/mb-init-review-result.schema.json +396 -0
  255. package/dist/schemas/mb-init-verify-result.schema.json +391 -0
  256. package/dist/schemas/mb-upgrade-stage-result.schema.json +863 -0
  257. package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
  258. package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
  259. package/dist/schemas/memory-composition-work-result.schema.json +38 -0
  260. package/dist/schemas/memory-repair-work-result.schema.json +56 -0
  261. package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
  262. package/dist/schemas/memory-review-work-result.schema.json +43 -0
  263. package/dist/schemas/model-catalog.schema.json +153 -0
  264. package/dist/schemas/plan-review-decision.schema.json +12 -3
  265. package/dist/schemas/plan-review-result.schema.json +2 -2
  266. package/dist/schemas/profile-settings.schema.json +122 -0
  267. package/dist/schemas/project-flow-pack-manifest.schema.json +2 -2
  268. package/dist/schemas/release-impact.schema.json +3 -3
  269. package/dist/schemas/release-manifest.schema.json +291 -0
  270. package/dist/schemas/review-fix-stage-result.schema.json +210 -0
  271. package/dist/schemas/run-control-receipt.schema.json +119 -0
  272. package/dist/schemas/run-control-request.schema.json +36 -0
  273. package/dist/schemas/run-engine-binding.schema.json +1 -1
  274. package/dist/schemas/stage-start-response.schema.json +4 -0
  275. package/dist/schemas/vnext-protocol-plan.schema.json +3 -3
  276. package/dist/services/accepted-intent.js +139 -0
  277. package/dist/services/assigned-lifecycle.js +382 -0
  278. package/dist/services/branch-context.js +3 -3
  279. package/dist/services/canon.js +54 -15
  280. package/dist/services/check-environment.js +21 -0
  281. package/dist/services/check-runner-evidence.js +344 -0
  282. package/dist/services/check-runner-proof.js +373 -0
  283. package/dist/services/cleanup.js +133 -40
  284. package/dist/services/cli-operation-classifier.js +32 -64
  285. package/dist/services/cli-upgrade-allowlist.js +27 -0
  286. package/dist/services/code-checks.js +1426 -121
  287. package/dist/services/codex-capacity.js +367 -0
  288. package/dist/services/codex-hook-delivery.js +41 -0
  289. package/dist/services/command-context.js +80 -0
  290. package/dist/services/compatibility-preflight.js +16 -3
  291. package/dist/services/config.js +11 -8
  292. package/dist/services/continuation-outcome.js +25 -0
  293. package/dist/services/controller-child-capacity.js +71 -0
  294. package/dist/services/controller-child-observer.js +121 -0
  295. package/dist/services/controller-child-repair.js +117 -0
  296. package/dist/services/controller-execution.js +97 -0
  297. package/dist/services/controller-fanout.js +277 -0
  298. package/dist/services/controller-memory-task.js +45 -0
  299. package/dist/services/controller-memory-worker.js +51 -0
  300. package/dist/services/controller-result-authority.js +127 -0
  301. package/dist/services/controller-work-failure.js +198 -0
  302. package/dist/services/dashboard.js +145 -58
  303. package/dist/services/delivery-access.js +123 -0
  304. package/dist/services/delivery-approval.js +68 -0
  305. package/dist/services/delivery-artifact.js +86 -0
  306. package/dist/services/delivery-checks.js +178 -0
  307. package/dist/services/delivery-execution.js +181 -0
  308. package/dist/services/delivery-intents.js +212 -0
  309. package/dist/services/delivery-operation.js +81 -0
  310. package/dist/services/delivery-policy.js +91 -0
  311. package/dist/services/delivery-procedures.js +43 -0
  312. package/dist/services/delivery-request.js +99 -0
  313. package/dist/services/delivery-result.js +144 -0
  314. package/dist/services/delivery-stage-commands.js +26 -0
  315. package/dist/services/delivery-stage-entry.js +56 -0
  316. package/dist/services/delivery-stage-handlers.js +135 -0
  317. package/dist/services/delivery-stage-results.js +94 -0
  318. package/dist/services/descriptor-coordinator-session.js +37 -0
  319. package/dist/services/descriptor-root-work.js +53 -0
  320. package/dist/services/descriptor-run-settlement.js +107 -0
  321. package/dist/services/descriptor-run-start.js +495 -0
  322. package/dist/services/descriptor-stage-coordinator.js +318 -0
  323. package/dist/services/descriptor-stage-settlement.js +268 -0
  324. package/dist/services/descriptor-stage-start.js +175 -0
  325. package/dist/services/diagnostic-evidence.js +73 -0
  326. package/dist/services/diagnostic-repair-intake.js +123 -0
  327. package/dist/services/diagnostic-repair-source-intake.js +102 -0
  328. package/dist/services/diagnostic-report-publication.js +72 -0
  329. package/dist/services/diagnostic-report.js +97 -0
  330. package/dist/services/diagnostic-run-bundle.js +113 -0
  331. package/dist/services/diagnostic-snapshot.js +159 -0
  332. package/dist/services/diagnostic-stage-handlers.js +109 -0
  333. package/dist/services/diagnostic-stage-results.js +158 -0
  334. package/dist/services/diagnostic-start.js +134 -0
  335. package/dist/services/diagnostic-work-batch.js +34 -0
  336. package/dist/services/diagnostic-work-collection.js +97 -0
  337. package/dist/services/diagnostic-work-registration.js +101 -0
  338. package/dist/services/diagnostic-work-results.js +93 -0
  339. package/dist/services/discovery/agy-discovery.js +2 -0
  340. package/dist/services/discovery/codex-discovery.js +2 -0
  341. package/dist/services/discovery/droid-discovery.js +2 -0
  342. package/dist/services/discovery/grok-discovery.js +2 -0
  343. package/dist/services/discovery/opencode-discovery.js +2 -0
  344. package/dist/services/discovery/static.js +31 -0
  345. package/dist/services/discovery/zcode-discovery.js +2 -0
  346. package/dist/services/distill-document-publication.js +280 -0
  347. package/dist/services/distill-promotion.js +197 -0
  348. package/dist/services/distill-publication-custody.js +162 -0
  349. package/dist/services/distill-stage-handlers.js +249 -0
  350. package/dist/services/distill-stage-results.js +105 -0
  351. package/dist/services/distill-user-inputs.js +4 -0
  352. package/dist/services/distill-work-batch.js +42 -0
  353. package/dist/services/distill-work-collection.js +74 -0
  354. package/dist/services/distill-work-registration.js +93 -0
  355. package/dist/services/distill-work-results.js +98 -0
  356. package/dist/services/engines.js +354 -163
  357. package/dist/services/eval-snapshots.js +1326 -150
  358. package/dist/services/execution-bundles.js +275 -0
  359. package/dist/services/execution-policy.js +185 -0
  360. package/dist/services/executor-onboarding.js +56 -0
  361. package/dist/services/external-work-launch.js +316 -0
  362. package/dist/services/flow-catalog.js +54 -0
  363. package/dist/services/flow-descriptors.js +82 -0
  364. package/dist/services/frozen-engine.js +404 -0
  365. package/dist/services/generic-execution.js +165 -0
  366. package/dist/services/harness-adapter.js +342 -35
  367. package/dist/services/harness-config.js +2 -0
  368. package/dist/services/harness-discovery.js +29 -0
  369. package/dist/services/harness-doctor.js +75 -0
  370. package/dist/services/harness-probe-effects.js +51 -0
  371. package/dist/services/harness-version-probe.js +100 -0
  372. package/dist/services/hook-memory-routing.js +188 -0
  373. package/dist/services/hook-recovery-guard.js +14 -0
  374. package/dist/services/hook-session-observation.js +24 -0
  375. package/dist/services/hooks.js +813 -327
  376. package/dist/services/hybrid-contracts.js +479 -0
  377. package/dist/services/hybrid-digest.js +14 -0
  378. package/dist/services/ids.js +29 -1
  379. package/dist/services/installation-lock.js +95 -0
  380. package/dist/services/installed-flow-source.js +261 -0
  381. package/dist/services/interactive-attached-session.js +215 -0
  382. package/dist/services/interactive-baseline-custody.js +54 -0
  383. package/dist/services/interactive-before-versions.js +148 -0
  384. package/dist/services/interactive-bundle-data.js +85 -0
  385. package/dist/services/interactive-checks.js +179 -0
  386. package/dist/services/interactive-execution.js +33 -0
  387. package/dist/services/interactive-finish-integration.js +236 -0
  388. package/dist/services/interactive-git-baseline.js +230 -0
  389. package/dist/services/interactive-git-dispatch.js +278 -0
  390. package/dist/services/interactive-input-delivery.js +82 -0
  391. package/dist/services/interactive-mutation-scope.js +231 -0
  392. package/dist/services/interactive-request.js +287 -0
  393. package/dist/services/interactive-run-bundle.js +109 -0
  394. package/dist/services/interactive-stage-entry.js +41 -0
  395. package/dist/services/interactive-stage-handlers.js +289 -0
  396. package/dist/services/interactive-stage-observation.js +136 -0
  397. package/dist/services/interactive-stage-results.js +111 -0
  398. package/dist/services/interactive-user-inputs.js +142 -0
  399. package/dist/services/interactive-work-batch.js +43 -0
  400. package/dist/services/interactive-work-collection.js +119 -0
  401. package/dist/services/interactive-work-completion.js +180 -0
  402. package/dist/services/interactive-work-context.js +249 -0
  403. package/dist/services/interactive-work-history.js +112 -0
  404. package/dist/services/interactive-work-registration.js +124 -0
  405. package/dist/services/interactive-work-results.js +115 -0
  406. package/dist/services/interactive-work-start.js +155 -0
  407. package/dist/services/lanes.js +78 -65
  408. package/dist/services/lifecycle-command.js +1 -288
  409. package/dist/services/lifecycle-contract.js +1 -0
  410. package/dist/services/lifecycle-invocations.js +2549 -0
  411. package/dist/services/managed-daemon-binding.js +129 -0
  412. package/dist/services/managed-lease-monitor.js +133 -0
  413. package/dist/services/managed-processes.js +449 -69
  414. package/dist/services/memory-accepted-composition.js +78 -0
  415. package/dist/services/memory-baseline-preservation.js +65 -0
  416. package/dist/services/memory-completed-correction-wave.js +328 -0
  417. package/dist/services/memory-compose-handler.js +380 -0
  418. package/dist/services/memory-composition-acceptance.js +375 -0
  419. package/dist/services/memory-composition-graph.js +165 -0
  420. package/dist/services/memory-composition-registration.js +161 -0
  421. package/dist/services/memory-composition-work-custody.js +156 -0
  422. package/dist/services/memory-composition-work-results.js +108 -0
  423. package/dist/services/memory-corrected-review-acceptance.js +129 -0
  424. package/dist/services/memory-corrected-review-batch.js +37 -0
  425. package/dist/services/memory-corrected-review-findings.js +108 -0
  426. package/dist/services/memory-corrected-review-inputs.js +215 -0
  427. package/dist/services/memory-corrected-review-projection.js +78 -0
  428. package/dist/services/memory-corrected-review-receipt.js +178 -0
  429. package/dist/services/memory-corrected-review-registration.js +192 -0
  430. package/dist/services/memory-correction-check-receipt.js +235 -0
  431. package/dist/services/memory-correction-input-owner.js +6 -0
  432. package/dist/services/memory-custody-snapshot.js +36 -0
  433. package/dist/services/memory-discover-handler.js +104 -0
  434. package/dist/services/memory-finish-evidence.js +457 -0
  435. package/dist/services/memory-finish-handler.js +229 -0
  436. package/dist/services/memory-finish-integration.js +491 -0
  437. package/dist/services/memory-finish-readiness.js +169 -0
  438. package/dist/services/memory-fix-finish-integration.js +129 -0
  439. package/dist/services/memory-fix-git-dispatch.js +139 -0
  440. package/dist/services/memory-fix-intake-custody.js +11 -0
  441. package/dist/services/memory-fix-intake-settlement.js +127 -0
  442. package/dist/services/memory-fix-publication.js +196 -0
  443. package/dist/services/memory-fix-repair-admission.js +116 -0
  444. package/dist/services/memory-fix-request.js +141 -0
  445. package/dist/services/memory-fix-run-bundle.js +83 -0
  446. package/dist/services/memory-fix-scope.js +78 -0
  447. package/dist/services/memory-fix-sources.js +85 -0
  448. package/dist/services/memory-fix-stage-entry.js +24 -0
  449. package/dist/services/memory-fix-stage-handlers.js +282 -0
  450. package/dist/services/memory-fix-stage-results.js +106 -0
  451. package/dist/services/memory-fix-workspace.js +127 -0
  452. package/dist/services/memory-flow-user-inputs.js +88 -0
  453. package/dist/services/memory-git-integration.js +220 -0
  454. package/dist/services/memory-historical-corrected-review.js +212 -0
  455. package/dist/services/memory-historical-original-review.js +143 -0
  456. package/dist/services/memory-historical-repair-registration.js +105 -0
  457. package/dist/services/memory-historical-second-review.js +147 -0
  458. package/dist/services/memory-init-bootstrap-readiness.js +210 -0
  459. package/dist/services/memory-init-contexts.js +181 -0
  460. package/dist/services/memory-init-controller-start.js +119 -0
  461. package/dist/services/memory-init-engine-release.js +223 -0
  462. package/dist/services/memory-init-git-policy.js +165 -0
  463. package/dist/services/memory-init-lint-capability.js +203 -0
  464. package/dist/services/memory-init-native-capacity.js +309 -0
  465. package/dist/services/memory-init-preflight.js +334 -0
  466. package/dist/services/memory-init-project-bootstrap.js +599 -0
  467. package/dist/services/memory-init-request-candidate.js +213 -0
  468. package/dist/services/memory-init-request-input.js +82 -0
  469. package/dist/services/memory-init-resource-storage.js +125 -0
  470. package/dist/services/memory-init-run-allocation.js +81 -0
  471. package/dist/services/memory-init-run-bundle.js +135 -0
  472. package/dist/services/memory-init-start.js +181 -0
  473. package/dist/services/memory-init-startup-custody.js +80 -0
  474. package/dist/services/memory-init-startup-input.js +240 -0
  475. package/dist/services/memory-init-storage.js +91 -0
  476. package/dist/services/memory-init-stores.js +359 -0
  477. package/dist/services/memory-init-worktrunk-capability.js +174 -0
  478. package/dist/services/memory-layer-publication.js +611 -0
  479. package/dist/services/memory-layer.js +225 -0
  480. package/dist/services/memory-lint-config.js +194 -0
  481. package/dist/services/memory-native-review-copy.js +127 -0
  482. package/dist/services/memory-normal-flow-entry.js +87 -0
  483. package/dist/services/memory-ordinary-defaults.js +129 -0
  484. package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
  485. package/dist/services/memory-preflight-handler.js +274 -0
  486. package/dist/services/memory-repair-current-view.js +299 -0
  487. package/dist/services/memory-repair-document-delta.js +489 -0
  488. package/dist/services/memory-repair-history.js +496 -0
  489. package/dist/services/memory-repair-physical-binding.js +194 -0
  490. package/dist/services/memory-repair-publication-files.js +152 -0
  491. package/dist/services/memory-repair-publication-intent.js +27 -0
  492. package/dist/services/memory-repair-publication-plan.js +162 -0
  493. package/dist/services/memory-repair-publication-source.js +225 -0
  494. package/dist/services/memory-repair-publication.js +795 -0
  495. package/dist/services/memory-repair-registration.js +240 -0
  496. package/dist/services/memory-repair-work-baseline.js +415 -0
  497. package/dist/services/memory-repair-work-completion.js +117 -0
  498. package/dist/services/memory-repair-work-custody.js +73 -0
  499. package/dist/services/memory-repair-work-results.js +108 -0
  500. package/dist/services/memory-repair-workspace.js +261 -0
  501. package/dist/services/memory-repair-writer-copy.js +736 -0
  502. package/dist/services/memory-result-binding.js +239 -0
  503. package/dist/services/memory-retained-review-authority.js +138 -0
  504. package/dist/services/memory-retained-review-results.js +70 -0
  505. package/dist/services/memory-retained-second-baseline.js +102 -0
  506. package/dist/services/memory-retained-second-repairs.js +162 -0
  507. package/dist/services/memory-review-acceptance.js +214 -0
  508. package/dist/services/memory-review-correction-plan.js +206 -0
  509. package/dist/services/memory-review-handler.js +585 -0
  510. package/dist/services/memory-review-inputs.js +246 -0
  511. package/dist/services/memory-review-limits.js +10 -0
  512. package/dist/services/memory-review-receipt.js +180 -0
  513. package/dist/services/memory-review-registration.js +117 -0
  514. package/dist/services/memory-review-work-custody.js +126 -0
  515. package/dist/services/memory-review-work-input.js +91 -0
  516. package/dist/services/memory-review-work-results.js +95 -0
  517. package/dist/services/memory-second-corrected-review-inputs.js +167 -0
  518. package/dist/services/memory-second-correction-plan.js +77 -0
  519. package/dist/services/memory-second-repair-baseline.js +91 -0
  520. package/dist/services/memory-second-repair-launch.js +614 -0
  521. package/dist/services/memory-second-repair-registration.js +88 -0
  522. package/dist/services/memory-second-repair-source.js +187 -0
  523. package/dist/services/memory-second-review-acceptance.js +115 -0
  524. package/dist/services/memory-source-observations.js +117 -0
  525. package/dist/services/memory-stage-dispatch.js +65 -0
  526. package/dist/services/memory-stage-results.js +290 -0
  527. package/dist/services/memory-tool-probe.js +25 -0
  528. package/dist/services/memory-upgrade-analysis-handler.js +243 -0
  529. package/dist/services/memory-upgrade-bootstrap-readiness.js +251 -0
  530. package/dist/services/memory-upgrade-evidence.js +100 -0
  531. package/dist/services/memory-upgrade-inventory.js +442 -0
  532. package/dist/services/memory-upgrade-publication-custody.js +73 -0
  533. package/dist/services/memory-upgrade-publication.js +413 -0
  534. package/dist/services/memory-upgrade-selection.js +430 -0
  535. package/dist/services/memory-upgrade-start.js +60 -0
  536. package/dist/services/memory-upgrade-storage-readiness.js +340 -0
  537. package/dist/services/memory-verification-acceptance.js +156 -0
  538. package/dist/services/memory-verification-checks.js +317 -0
  539. package/dist/services/memory-verification-receipt.js +160 -0
  540. package/dist/services/memory-verify-handler.js +137 -0
  541. package/dist/services/memory-work-result-json.js +12 -0
  542. package/dist/services/memory-work-result-preparation.js +64 -0
  543. package/dist/services/merge-queue.js +228 -149
  544. package/dist/services/merge-server.js +163 -35
  545. package/dist/services/migrations.js +164 -114
  546. package/dist/services/model-catalog.js +109 -0
  547. package/dist/services/model-discovery.js +46 -0
  548. package/dist/services/native-daemon-history.js +50 -0
  549. package/dist/services/native-session-control.js +39 -0
  550. package/dist/services/operator-profiles.js +236 -0
  551. package/dist/services/physical-startup.js +45 -0
  552. package/dist/services/plan-runtime.js +26 -11
  553. package/dist/services/plans.js +28 -25
  554. package/dist/services/project-flow-source.js +195 -0
  555. package/dist/services/project-git-integration.js +92 -0
  556. package/dist/services/project-registry.js +97 -0
  557. package/dist/services/project-summary.js +1 -1
  558. package/dist/services/projects.js +17 -87
  559. package/dist/services/prompt-delivery.js +71 -0
  560. package/dist/services/prompts.js +28 -17
  561. package/dist/services/protocols.js +163 -87
  562. package/dist/services/provider-capacity.js +463 -0
  563. package/dist/services/recovery-observation-budget.js +121 -0
  564. package/dist/services/recovery-snapshot-database.js +588 -0
  565. package/dist/services/release-archive-producer.js +52 -0
  566. package/dist/services/release-archive.js +143 -0
  567. package/dist/services/release-cache.js +150 -0
  568. package/dist/services/release-compatibility.js +18 -0
  569. package/dist/services/release-download.js +67 -0
  570. package/dist/services/release-envelope.js +104 -0
  571. package/dist/services/release-manifest.js +45 -0
  572. package/dist/services/release-payload.js +114 -0
  573. package/dist/services/release-producer.js +63 -0
  574. package/dist/services/release-provenance.js +160 -0
  575. package/dist/services/release-registry.js +66 -0
  576. package/dist/services/release-source.js +194 -0
  577. package/dist/services/repair-intents.js +29 -0
  578. package/dist/services/repair-receipt.js +13 -0
  579. package/dist/services/retained-native-hook.js +274 -0
  580. package/dist/services/review-copy.js +165 -0
  581. package/dist/services/review-deferral.js +23 -0
  582. package/dist/services/review-fix-handoff.js +82 -0
  583. package/dist/services/review-fix-intake-custody.js +17 -0
  584. package/dist/services/review-fix-stage-entry.js +43 -0
  585. package/dist/services/review-fix-stage-handlers.js +176 -0
  586. package/dist/services/review-fix-stage-results.js +86 -0
  587. package/dist/services/run-control-receipt.js +56 -0
  588. package/dist/services/run-control-worker.js +469 -0
  589. package/dist/services/run-control.js +1109 -0
  590. package/dist/services/run-controller-adapter.js +434 -0
  591. package/dist/services/run-controller-capture.js +186 -0
  592. package/dist/services/run-controller-process.js +226 -0
  593. package/dist/services/run-controller-recovery.js +335 -0
  594. package/dist/services/run-controller-state.js +106 -0
  595. package/dist/services/run-controller.js +1717 -0
  596. package/dist/services/run-engine-bindings.js +1 -1
  597. package/dist/services/run-fork.js +147 -0
  598. package/dist/services/run-health.js +149 -0
  599. package/dist/services/run-observations.js +152 -0
  600. package/dist/services/run-projection.js +22 -64
  601. package/dist/services/run-recovery-guard.js +107 -0
  602. package/dist/services/run-recovery-runtime.js +112 -0
  603. package/dist/services/run-recovery.js +485 -0
  604. package/dist/services/run-start-custody.js +189 -0
  605. package/dist/services/run-timeline.js +59 -0
  606. package/dist/services/runs.js +996 -271
  607. package/dist/services/runtime-budget.js +446 -0
  608. package/dist/services/runtime-command.js +43 -0
  609. package/dist/services/runtime-scope-capture.js +52 -0
  610. package/dist/services/runtime-scope-control.js +468 -0
  611. package/dist/services/runtime-scope-resume.js +605 -0
  612. package/dist/services/runtime-scope-stop.js +211 -0
  613. package/dist/services/runtime-scope-worker.js +314 -0
  614. package/dist/services/runtime-service.js +19 -14
  615. package/dist/services/schema-validation.js +10 -8
  616. package/dist/services/scope-writer-cleanup.js +27 -0
  617. package/dist/services/sessions.js +37 -91
  618. package/dist/services/setup.js +427 -0
  619. package/dist/services/stage-blocker.js +17 -7
  620. package/dist/services/stage-context.js +240 -18
  621. package/dist/services/stage-handlers.js +141 -0
  622. package/dist/services/stage-lifecycle.js +156 -119
  623. package/dist/services/stage-pause.js +222 -94
  624. package/dist/services/stage-report-renderer.js +230 -6
  625. package/dist/services/stage-work-graph.js +52 -0
  626. package/dist/services/technical-notes.js +31 -0
  627. package/dist/services/tooling.js +111 -44
  628. package/dist/services/usage.js +49 -101
  629. package/dist/services/verification-matrix.js +393 -0
  630. package/dist/services/version-status.js +1 -1
  631. package/dist/services/vnext-code-review.js +302 -91
  632. package/dist/services/vnext-code.js +325 -251
  633. package/dist/services/vnext-contracts.js +10 -1
  634. package/dist/services/vnext-execution-profile.js +80 -5
  635. package/dist/services/vnext-fanout.js +399 -20
  636. package/dist/services/vnext-merge.js +336 -114
  637. package/dist/services/vnext-plan-review.js +288 -133
  638. package/dist/services/vnext-plan.js +230 -106
  639. package/dist/services/vnext-protocolize.js +534 -96
  640. package/dist/services/vnext-specify.js +131 -84
  641. package/dist/services/vnext-workspace-policy.js +7 -2
  642. package/dist/services/work-registry.js +1950 -215
  643. package/dist/services/work-retry-context.js +55 -0
  644. package/dist/services/workspace-bootstrap.js +53 -15
  645. package/dist/services/workspace-files.js +85 -0
  646. package/dist/services/worktrees.js +108 -48
  647. package/dist/shared/entity-references.js +1 -0
  648. package/dist/shared/errors.js +27 -0
  649. package/dist/storage/agent-output.js +26 -0
  650. package/dist/storage/data-preservation.js +65 -0
  651. package/dist/storage/database.js +931 -40
  652. package/dist/storage/foreign-key-transaction.js +39 -0
  653. package/dist/storage/immutable-input.js +45 -0
  654. package/dist/storage/import-guard.js +159 -0
  655. package/dist/storage/memory-upgrade-schema-bootstrap.js +38 -0
  656. package/dist/storage/native-cleanup.js +52 -0
  657. package/dist/storage/paired-writer-migration.js +424 -0
  658. package/dist/storage/paths.js +17 -4
  659. package/dist/storage/projection-lock.js +73 -0
  660. package/dist/storage/work-references.js +23 -0
  661. package/dist/storage/writer-contract.js +96 -0
  662. package/dist/storage/writer-migration.js +346 -0
  663. package/dist/storage/writer-restore.js +217 -0
  664. package/dist/verification-components.json +384 -0
  665. package/package.json +52 -13
  666. package/tools/create-canon-release.mjs +33 -0
  667. package/tools/probe-codex-history.mjs +37 -0
  668. package/tools/produce-hybrid-release.mjs +41 -0
  669. package/tools/repair-paused-run-status.mjs +84 -0
  670. package/tools/verification-jobs.mjs +342 -0
@@ -0,0 +1,434 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { AppError } from "../shared/errors.js";
5
+ import { adapterSessionId, runHarnessAdapter } from "./harness-adapter.js";
6
+ import { runtimeHarness } from "./execution-policy.js";
7
+ import { appendEvent, digest, digestBytes, errorRecord, requireRun } from "./run-controller-state.js";
8
+ import { managedProcessStatus } from "./managed-processes.js";
9
+ import { RECOVERY_POLICY as CAPACITY_POLICY, parseCapacityOperation } from "../harness-runtime/lib/provider-overload-policy.mjs";
10
+ import { recoveryObservationBudget } from "./recovery-observation-budget.js";
11
+ import { canonicalNativeOperation } from "../harness-runtime/lib/adapter-timeouts.mjs";
12
+ import { retainedDaemonReply } from "../harness-runtime/lib/daemon-observation.mjs";
13
+ import { readOperationRecord } from "../harness-runtime/lib/operation-progress.mjs";
14
+ import { readNativeDaemonState } from "./managed-daemon-binding.js";
15
+ import { validateCheckEnvironment } from "./check-environment.js";
16
+ import { controllerObligationAccepted, lateNativeFailure } from "./controller-result-authority.js";
17
+ import { recordTechnicalNote } from "./technical-notes.js";
18
+ /** A paused RUN admits only its controller's exact accepted answer Turn. */
19
+ export function controllerHitlAdmission(context, record, input) {
20
+ if (input.operation !== "session.prompt" || !input.operationId || !input.promptSha256)
21
+ return false;
22
+ if (!context.db.get("SELECT 1 FROM sqlite_schema WHERE name = 'run_controller_operations'"))
23
+ return false;
24
+ const row = context.db.get("SELECT * FROM run_controllers WHERE controller_id = ? AND project_id = ? AND run_id = ? AND status = 'waiting_for_user'", [record.owner_id, record.project_id, record.run_id]);
25
+ if (!row || row.generation !== JSON.parse(record.metadata_json).run_generation)
26
+ return false;
27
+ const suffix = `:prompt:${row.generation}`;
28
+ const successor = parseCapacityOperation(input.operationId);
29
+ const baseId = successor.root;
30
+ if (!baseId.endsWith(suffix))
31
+ return false;
32
+ if (successor.ordinal > 0) {
33
+ const ordinal = successor.ordinal;
34
+ const predecessorId = ordinal === 1 ? baseId : `${baseId}:capacity:${ordinal - 1}:session.prompt`;
35
+ const predecessor = context.db.get("SELECT status, receipt_json FROM run_controller_operations WHERE operation_id = ? AND controller_id = ? AND generation = ?", [predecessorId, row.controller_id, row.generation]);
36
+ if (predecessor?.status !== "failed" || !predecessor.receipt_json)
37
+ return false;
38
+ let retained;
39
+ try {
40
+ retained = JSON.parse(predecessor.receipt_json);
41
+ }
42
+ catch {
43
+ return false;
44
+ }
45
+ if (retained.capacity_intent?.predecessor !== predecessorId || retained.capacity_intent.operation_id !== input.operationId || retained.capacity_intent.ordinal !== ordinal)
46
+ return false;
47
+ if (retained.capacity_intent.policy !== CAPACITY_POLICY)
48
+ return false;
49
+ if (!retained.capacity_intent.not_before || !Number.isFinite(Date.parse(retained.capacity_intent.not_before)) || Date.parse(retained.capacity_intent.not_before) > Date.parse(context.now()) || retained.capacity_intent.prompt_sha256 !== input.promptSha256)
50
+ return false;
51
+ }
52
+ const state = JSON.parse(row.state_json);
53
+ const session = state.current_session === null ? undefined : state.sessions[state.current_session];
54
+ if (!session || session.stopped || session.id !== input.nativeSessionId || session.state_dir !== input.stateDir || session.owner.owner_id !== record.owner_id)
55
+ return false;
56
+ const operation = (id) => context.db.get("SELECT input_json, input_hash FROM run_controller_operations WHERE operation_id = ? AND controller_id = ? AND generation = ? AND status = 'dispatching'", [id, row.controller_id, row.generation]);
57
+ const answer = context.db.get("SELECT input_json, input_hash FROM run_controller_operations WHERE operation_id = ? AND controller_id = ? AND generation <= ? AND status = 'accepted'", [baseId.slice(0, -suffix.length), row.controller_id, row.generation]);
58
+ const prompt = operation(input.operationId);
59
+ if (!answer || !prompt)
60
+ return false;
61
+ const accepted = JSON.parse(answer.input_json);
62
+ // The phase is a mutable journal projection, not part of the frozen input.
63
+ const { dispatch_phase, ...dispatch } = JSON.parse(prompt.input_json);
64
+ if (dispatch_phase !== "external_dispatch_possible")
65
+ return false;
66
+ const run = context.db.get("SELECT index_json FROM runs WHERE project_id = ? AND id = ?", [record.project_id, record.run_id]);
67
+ const stage = run && JSON.parse(run.index_json).stage_runs.find(item => item.stage === accepted.stage);
68
+ if (accepted.action !== "user_answer" || state.stage !== accepted.stage || stage?.status !== "paused" || !stage.pause || stage.pause.answer_path || stage.pause.id !== accepted.pause_id || stage.pause.work_id !== accepted.work_id)
69
+ return false;
70
+ if (answer.input_hash !== digest({ pause_id: accepted.pause_id, answer_sha256: accepted.sha256 }) || prompt.input_hash !== digest(dispatch))
71
+ return false;
72
+ const value = (option) => dispatch.args.includes(option) ? dispatch.args[dispatch.args.indexOf(option) + 1] : undefined;
73
+ if (dispatch.owner !== record.owner_id || dispatch.state_dir !== input.stateDir || dispatch.args[0] !== "session" || dispatch.args[1] !== "prompt" || value("--session-id") !== input.nativeSessionId || dispatch.prompt_sha256 !== input.promptSha256 || !value("--prompt-file"))
74
+ return false;
75
+ return digestBytes(fs.readFileSync(accepted.file)) === accepted.sha256 && digestBytes(fs.readFileSync(value("--prompt-file"))) === input.promptSha256;
76
+ }
77
+ export function sessionArguments(context, manifest, session) {
78
+ const profile = session.profile;
79
+ return ["--dd-flow-bin", manifest.flow_executable, "--dd-flow-home", context.ddFlowHome, "--project-root", manifest.request.project_root, "--state-dir", session.state_dir, "--journal", session.journal, "--cwd", session.cwd, "--provider", profile.provider, "--model", profile.model, "--reasoning", profile.reasoning, "--mode", profile.mode, "--permission", profile.permission, ...manifest.adapters[runtimeHarness(profile)].runtime_args, "--json"];
80
+ }
81
+ export function controllerEnvironment(context, manifest, session) {
82
+ const env = { ...context.env, ...validateCheckEnvironment(manifest.check_environment), DD_FLOW_HOME: context.ddFlowHome, DD_FLOW_BIN: manifest.flow_executable, DD_FLOW_RESOURCE_HOME: manifest.resource_home, DD_FLOW_RUNTIME_BUDGET: manifest.budget ? JSON.stringify(manifest.budget) : undefined };
83
+ for (const key of ["DD_FLOW_CONTROLLER_TOKEN", "DD_FLOW_CONTROL_TOKEN", "DD_FLOW_DAEMON_ID", "DD_FLOW_RUNTIME_OWNER", "DD_FLOW_WORK_ID", "DD_FLOW_SESSION_ID", "CODEX_THREAD_ID"])
84
+ delete env[key];
85
+ if (session?.codex_home)
86
+ env.CODEX_HOME = session.codex_home;
87
+ return env;
88
+ }
89
+ function settlement(value) {
90
+ const state = value.settlement;
91
+ return state && typeof state === "object" && !Array.isArray(state) ? state : null;
92
+ }
93
+ function settlementInspectArgs(args) {
94
+ const values = ["session", "inspect"];
95
+ for (let index = 2; index < args.length; index += 1) {
96
+ const value = args[index];
97
+ if (["--prompt", "--prompt-file", "--answers-file", "--target-json"].includes(value)) {
98
+ index += 1;
99
+ continue;
100
+ }
101
+ values.push(value);
102
+ }
103
+ return values;
104
+ }
105
+ function settlementRetryArgs(args, operationId) {
106
+ const stateDir = args[args.indexOf("--state-dir") + 1];
107
+ if (!stateDir)
108
+ throw new AppError("settlement_recovery_required", "Harness settlement has no state directory", 1, { operation_id: operationId });
109
+ return ["daemon", "operation", "settle", "--state-dir", stateDir, "--operation-id", operationId, "--json"];
110
+ }
111
+ function operationInspectArgs(args, operationId) {
112
+ const stateDir = args[args.indexOf("--state-dir") + 1];
113
+ if (!stateDir)
114
+ throw new AppError("controller_operation_binding_unknown", "Harness operation has no state directory", 1, { operation_id: operationId });
115
+ return ["daemon", "operation", "--state-dir", stateDir, "--operation-id", operationId, "--json"];
116
+ }
117
+ function expectedMethod(args, session) {
118
+ return canonicalNativeOperation(runtimeHarness(session.profile), `${args[0]}.${args[1] === "status" ? "inspect" : args[1]}`);
119
+ }
120
+ function recoveryAuthorityError(error) {
121
+ return ["session_identity_mismatch", "profile_integrity_violation", "controller_operation_mismatch", "operation_conflict", "operation_cancelled", "settlement_recovery_required"].includes(String(error?.code));
122
+ }
123
+ /** A retained native effect is not permission to continue under a new daemon. */
124
+ async function recoveredSessionReceipt(context, session, args, operationId, receipt, binding = {}, signal, inspection) {
125
+ const method = expectedMethod(args, session);
126
+ if (!["session.create", "session.prompt", "session.start", "session.fork", "session.resume"].includes(method))
127
+ return receipt;
128
+ const requested = await readOperationRecord(session.state_dir, operationId, "requested.json");
129
+ signal?.throwIfAborted();
130
+ const daemon = fs.existsSync(path.join(session.state_dir, "daemon.json")) ? readNativeDaemonState(session.state_dir) : null;
131
+ // Old minimal adapters have neither owned operation records nor daemon
132
+ // ownership metadata. Missing a modern record cannot downgrade to that path.
133
+ const modern = requested?.owner_id || requested && Object.hasOwn(requested, "params_sha256") || requested?.generation != null || daemon?.config?.runtime_owner?.owner_id
134
+ || managedProcessStatus({ ...context, env: { ...context.env, ...(session.owner.resource_home ? { DD_FLOW_RESOURCE_HOME: session.owner.resource_home } : {}) } }).some(record => {
135
+ const metadata = JSON.parse(record.metadata_json);
136
+ return record.kind.endsWith("-daemon") && record.owner_id === session.owner.owner_id && record.project_id === session.owner.project_id && record.run_id === session.owner.run_id
137
+ && metadata.state_dir === session.state_dir && metadata.dd_flow_home === session.owner.dd_flow_home && metadata.adapter_executable === session.owner.adapter_executable;
138
+ });
139
+ if (!modern)
140
+ return receipt;
141
+ const target = args.includes("--session-id") ? args[args.indexOf("--session-id") + 1] : undefined;
142
+ const retained = await retainedDaemonReply(session.state_dir, operationId, { ...binding, operation: method, owner_id: session.owner.owner_id, ...(target ? { session_id: target } : {}) });
143
+ signal?.throwIfAborted();
144
+ if (!retained || retained.reason)
145
+ throw new AppError("settlement_recovery_required", "Retained native outcome has no current dispatch authority", 1, { operation_id: operationId, native_outcome: "completed", native_result: retained?.outcome ?? receipt, settlement: retained?.settlement, reason: retained?.reason ?? "native_receipt_unavailable" });
146
+ if (inspection && settlement(inspection)?.state === "settled" && !retained.ready) {
147
+ const proof = inspection.settlement;
148
+ if (proof.source !== "inspection" || !Array.isArray(proof.operation_ids) || !proof.operation_ids.includes(operationId))
149
+ throw new AppError("settlement_recovery_required", "Fresh inspection does not settle the original retained operation", 1, { operation_id: operationId, native_outcome: "completed", native_result: retained.outcome, reason: "inspection_settlement_unbound", settlement: proof });
150
+ }
151
+ const result = retained.ready ? retained.value : retained.outcome;
152
+ if (!result || typeof result !== "object" || Array.isArray(result))
153
+ throw new AppError("controller_operation_mismatch", "Retained native outcome has no Session result", 1, { operation_id: operationId });
154
+ validateReceipt(result, session, args);
155
+ if (method === "session.create" && !adapterSessionId(result))
156
+ throw new AppError("session_identity_mismatch", "Retained creation outcome has no native Session identity", 1);
157
+ return { ...receipt, ...result, settlement: retained.ready ? retained.settlement ?? { state: "not_required" } : ["pending", "blocked"].includes(String(retained.settlement?.state)) ? retained.settlement : { ...retained.settlement, state: "pending", reason: retained.settlement?.reason ?? "settlement_evidence_required" } };
158
+ }
159
+ function validateReceipt(receipt, session, args) {
160
+ // `daemon start --session-id` names the retained state being reopened; the
161
+ // start receipt itself is a daemon lifecycle result and need not echo a
162
+ // provider Session identity. Only session operations promise that binding.
163
+ const target = args[0] === "session" && args.includes("--session-id") ? args[args.indexOf("--session-id") + 1] : null;
164
+ if (target && adapterSessionId(receipt) !== target)
165
+ throw new AppError("session_identity_mismatch", "Managed adapter reply belongs to another or unidentified Session", 1);
166
+ if (receipt.harness !== undefined && receipt.harness !== runtimeHarness(session.profile))
167
+ throw new AppError("profile_integrity_violation", "Managed adapter returned another harness identity", 1);
168
+ const fork = receipt.fork_receipt;
169
+ const forkUnproven = (args[0] === "session" && args[1] === "fork" && receipt.fork_continuity_error !== undefined)
170
+ || (fork && typeof fork === "object" && !Array.isArray(fork) && fork.history_prefix_proven === false);
171
+ if (forkUnproven) {
172
+ throw new AppError("fork_continuity_unproven", "Native fork exists but its source-history continuity is not proven", 1);
173
+ }
174
+ }
175
+ async function recoverCompletedOperation(context, manifest, session, executable, args, operationId, signal) {
176
+ // Creation has no Session ID yet, but its original operation ID is already
177
+ // retained. Inspect that receipt, never invoke native creation a second time.
178
+ if (expectedMethod(args, session) === "session.inspect")
179
+ return null;
180
+ // A detached adapter without a native daemon has no durable operation
181
+ // journal to inspect. Avoid a second adapter invocation in that case; the
182
+ // original failure remains outcome-unknown and the controller will fence it.
183
+ if (!fs.existsSync(path.join(session.state_dir, "daemon.json")))
184
+ return null;
185
+ let observed;
186
+ try {
187
+ observed = await runHarnessAdapter({ executable, args: operationInspectArgs(args, operationId), env: controllerEnvironment(context, manifest, session), operationId: `${operationId}:observe`, runtimeOwner: session.owner, timeoutMs: 30_000, ...(signal ? { signal } : {}) });
188
+ }
189
+ catch {
190
+ return null;
191
+ }
192
+ const target = args.includes("--session-id") ? args[args.indexOf("--session-id") + 1] : null;
193
+ const result = observed.result;
194
+ const primary = observed.primary_error ?? (["failed", "interrupted"].includes(String(observed.state)) ? observed.error : undefined);
195
+ if (observed.operation_id === operationId && observed.operation === expectedMethod(args, session)
196
+ && observed.state !== "completed" && (!target || observed.session_id === target)
197
+ && primary && typeof primary === "object" && !Array.isArray(primary)) {
198
+ const failure = primary;
199
+ if (typeof failure.code === "string" && typeof failure.message === "string") {
200
+ throw new AppError(failure.code, failure.message, 1, { ...(failure.details && typeof failure.details === "object" && !Array.isArray(failure.details) ? failure.details : {}), operation_id: operationId, effect: "unknown" });
201
+ }
202
+ }
203
+ if (observed.operation_id !== operationId || observed.operation !== expectedMethod(args, session) || observed.state !== "completed"
204
+ || !result || typeof result !== "object" || Array.isArray(result)
205
+ || target && (observed.session_id !== target || adapterSessionId(result) !== target))
206
+ return null;
207
+ return await recoveredSessionReceipt(context, session, args, operationId, { ...result, ...(settlement(observed) ? { settlement: settlement(observed) } : {}) }, Object.fromEntries(["generation", "params_sha256"].filter(key => observed[key] !== undefined).map(key => [key, observed[key]])), signal);
208
+ }
209
+ async function awaitSettlement(context, row, manifest, session, executable, args, operationId, initial, assertOwner, signal) {
210
+ let current = initial, delay = 250;
211
+ const observation = recoveryObservationBudget(initial);
212
+ observation.observe(initial);
213
+ const retainObservation = () => {
214
+ assertOwner?.();
215
+ const receipt = { ...initial, ...current, recovery_observation: observation.state() };
216
+ const changed = context.db.run("UPDATE run_controller_operations SET receipt_json = ?, updated_at = ? WHERE operation_id = ? AND controller_id = ? AND generation = ? AND EXISTS (SELECT 1 FROM run_controllers WHERE controller_id = ? AND owner_token = ? AND generation = ?)", [JSON.stringify(receipt), context.now(), operationId, row.controller_id, row.generation, row.controller_id, row.owner_token, row.generation]);
217
+ if (changed.changes !== 1)
218
+ throw new AppError("controller_owner_mismatch", "Controller lost ownership before settlement observation retention", 1);
219
+ };
220
+ while (["pending", "blocked"].includes(String(settlement(current)?.state))) {
221
+ if (signal?.aborted)
222
+ throw new AppError("harness_settlement_interrupted", "Harness settlement was interrupted", 1, { operation_id: operationId });
223
+ // A completed parent with live children is normal controller waiting, not
224
+ // failed bookkeeping. Keep its budget reserved until a later inspection.
225
+ if (["session.prompt", "session.inspect"].includes(expectedMethod(args, session)) && settlement(current)?.reason === "tree_unsettled")
226
+ return { ...initial, ...current, ...(initial.assistant_text !== undefined ? { assistant_text: initial.assistant_text } : {}) };
227
+ const exhausted = observation.exhausted();
228
+ retainObservation();
229
+ if (exhausted) {
230
+ // Final bounded read is observation, never another settlement mutation.
231
+ if (args.includes("--session-id")) {
232
+ assertOwner?.();
233
+ try {
234
+ const terminal = await runHarnessAdapter({ executable, args: settlementInspectArgs(args), env: controllerEnvironment(context, manifest, session), operationId: `${operationId}:settlement-final-inspect`, runtimeOwner: session.owner, timeoutMs: 30_000, ...(signal ? { signal } : {}) });
235
+ validateReceipt(terminal, session, args);
236
+ if (settlement(terminal)?.state === "settled") {
237
+ await recoveredSessionReceipt(context, session, args, operationId, initial, {}, signal, terminal);
238
+ assertOwner?.();
239
+ current = terminal;
240
+ break;
241
+ }
242
+ }
243
+ catch (error) {
244
+ if (recoveryAuthorityError(error))
245
+ throw error;
246
+ }
247
+ }
248
+ throw new AppError("settlement_recovery_required", "Completed provider operation requires settlement recovery", 1, { operation_id: operationId, settlement: settlement(current), recovery_observation: observation.state() });
249
+ }
250
+ await new Promise(resolve => setTimeout(resolve, Math.min(delay, observation.timeout())));
251
+ delay = Math.min(delay * 2, 8_000);
252
+ assertOwner?.();
253
+ if (observation.exhausted())
254
+ continue;
255
+ try {
256
+ // This only retries durable bookkeeping against the same operation
257
+ // receipt. It cannot replay the provider request.
258
+ const inspect = expectedMethod(args, session) === "session.inspect";
259
+ current = await runHarnessAdapter({ executable, args: inspect ? settlementInspectArgs(args) : settlementRetryArgs(args, operationId), env: controllerEnvironment(context, manifest, session), operationId: `${operationId}:settlement`, runtimeOwner: session.owner, timeoutMs: observation.timeout(), ...(signal ? { signal } : {}) });
260
+ if (inspect)
261
+ validateReceipt(current, session, args);
262
+ else
263
+ current = await recoveredSessionReceipt(context, session, args, operationId, current, Object.fromEntries(["generation", "params_sha256"].filter(key => current[key] !== undefined).map(key => [key, current[key]])), signal);
264
+ }
265
+ catch (error) {
266
+ if (recoveryAuthorityError(error))
267
+ throw error;
268
+ current = { settlement: { state: "pending", reason: "inspection_error", error: errorRecord(error) } };
269
+ }
270
+ observation.observe(current);
271
+ if (!(["pending", "blocked"].includes(String(settlement(current)?.state))))
272
+ continue;
273
+ // A receipt without final tree proof needs a fresh native inspection. Do
274
+ // it only after the receipt-only retry, and only when this is a session.
275
+ if (!args.includes("--session-id") || !["tree_unsettled", "settlement_evidence_required"].includes(String(settlement(current)?.reason)) || observation.exhausted())
276
+ continue;
277
+ try {
278
+ current = await runHarnessAdapter({ executable, args: settlementInspectArgs(args), env: controllerEnvironment(context, manifest, session), operationId: `${operationId}:settlement-inspect`, runtimeOwner: session.owner, timeoutMs: observation.timeout(), ...(signal ? { signal } : {}) });
279
+ validateReceipt(current, session, args);
280
+ await recoveredSessionReceipt(context, session, args, operationId, initial, {}, signal, current);
281
+ }
282
+ catch (error) {
283
+ if (recoveryAuthorityError(error))
284
+ throw error;
285
+ current = { settlement: { state: "pending", reason: "inspection_error", error: errorRecord(error) } };
286
+ }
287
+ observation.observe(current);
288
+ }
289
+ return adapterSessionId(current) ? { ...initial, ...current, ...(initial.assistant_text !== undefined ? { assistant_text: initial.assistant_text } : {}) } : { ...initial, settlement: settlement(current) };
290
+ }
291
+ export async function controllerAdapter(context, row, manifest, session, args, assertOwner, retainedOperationId, signal, reconfirmOwner, obligation) {
292
+ const executable = manifest.adapters[runtimeHarness(session.profile)].executable;
293
+ const promptFile = args.indexOf("--prompt-file"), inlinePrompt = args.indexOf("--prompt");
294
+ const promptSha256 = promptFile >= 0 ? digestBytes(fs.readFileSync(args[promptFile + 1])) : inlinePrompt >= 0 ? digestBytes(args[inlinePrompt + 1] ?? "") : undefined;
295
+ const priorInput = retainedOperationId ? context.db.get("SELECT input_json FROM run_controller_operations WHERE operation_id=? AND controller_id=? AND generation=?", [retainedOperationId, row.controller_id, row.generation]) : undefined;
296
+ const effectiveObligation = priorInput ? JSON.parse(priorInput.input_json).obligation : obligation;
297
+ // Committing an answer resumes a Stage; it does not finish the semantic
298
+ // work owed by that prompt. Preserve its provider error for same-Session recovery.
299
+ const acceptedPromptBoundary = (expected) => controllerObligationAccepted(context, row, expected.action === "resume" ? { ...expected, action: "finish" } : expected);
300
+ const input = { executable, args, owner: session.owner.owner_id, state_dir: session.state_dir, ...(args[0] === "session" && args[1] === "prompt" && promptSha256 ? { prompt_sha256: promptSha256 } : {}), ...(effectiveObligation ? { obligation: effectiveObligation } : {}) };
301
+ const prepared = retainedOperationId ? [] : context.db.all("SELECT operation_id FROM run_controller_operations WHERE controller_id = ? AND generation = ? AND input_hash = ? AND status = 'dispatching' AND json_extract(input_json, '$.dispatch_phase') = 'prepared'", [row.controller_id, row.generation, digest(input)]);
302
+ if (prepared.length > 1)
303
+ throw new AppError("controller_operation_conflict", "Multiple prepared intents require explicit reconciliation", 1);
304
+ const operationId = retainedOperationId ?? prepared[0]?.operation_id ?? `${row.controller_id}:${crypto.randomUUID()}`;
305
+ const now = context.now();
306
+ const existing = context.db.get("SELECT input_hash,input_json,status,receipt_json,error_json FROM run_controller_operations WHERE operation_id = ? AND controller_id = ? AND generation = ?", [operationId, row.controller_id, row.generation]);
307
+ if (existing?.input_hash && existing.input_hash !== digest(input))
308
+ throw new AppError("controller_operation_conflict", "Retained operation has different dispatch parameters", 1, { operation_id: operationId });
309
+ if (existing?.status === "completed" && existing.receipt_json) {
310
+ const receipt = JSON.parse(existing.receipt_json);
311
+ validateReceipt(receipt, session, args);
312
+ return receipt;
313
+ }
314
+ if (!existing) {
315
+ context.db.run("INSERT INTO run_controller_operations (operation_id, controller_id, generation, input_hash, input_json, status, created_at, updated_at) SELECT ?, ?, ?, ?, ?, 'dispatching', ?, ? WHERE EXISTS (SELECT 1 FROM run_controllers WHERE controller_id = ? AND owner_token = ? AND generation = ?)", [operationId, row.controller_id, row.generation, digest(input), JSON.stringify({ ...input, dispatch_phase: "prepared" }), now, now, row.controller_id, row.owner_token, row.generation]);
316
+ appendEvent(context, row.controller_id, "operation_requested", { operation_id: operationId, operation: args.slice(0, 2), session_id: session.id || null });
317
+ }
318
+ let phase = existing ? JSON.parse(existing.input_json).dispatch_phase : "prepared";
319
+ const retainPhase = (next) => {
320
+ const changed = context.db.run("UPDATE run_controller_operations SET input_json = ?, updated_at = ? WHERE operation_id = ? AND controller_id = ? AND generation = ? AND status <> 'completed' AND EXISTS (SELECT 1 FROM run_controllers WHERE controller_id = ? AND owner_token = ? AND generation = ?)", [JSON.stringify({ ...input, dispatch_phase: next }), context.now(), operationId, row.controller_id, row.generation, row.controller_id, row.owner_token, row.generation]);
321
+ if (changed.changes !== 1)
322
+ throw new AppError("controller_owner_mismatch", "Controller lost ownership before durable dispatch transition", 1, { operation_id: operationId });
323
+ phase = next;
324
+ };
325
+ try {
326
+ await reconfirmOwner?.();
327
+ assertOwner?.();
328
+ let receipt;
329
+ let recoveredOperation = false;
330
+ try {
331
+ const timeoutMs = 120_000;
332
+ if (existing && phase === "receipt_observed" && existing.receipt_json) {
333
+ // The exact input hash and committed receipt survive a controller
334
+ // crash. Complete settlement without replaying productive native IO.
335
+ receipt = JSON.parse(existing.receipt_json);
336
+ validateReceipt(receipt, session, args);
337
+ if (args[0] === "session" && args[1] === "create" && !adapterSessionId(receipt))
338
+ throw new AppError("session_identity_mismatch", "Retained creation receipt has no native Session identity", 1);
339
+ receipt = await recoveredSessionReceipt(context, session, args, operationId, receipt, {}, signal);
340
+ recoveredOperation = true;
341
+ }
342
+ else if (existing && phase !== "prepared") {
343
+ if (expectedMethod(args, session) === "session.inspect") {
344
+ // A failed read may be explicitly reobserved. Never do this for a
345
+ // materializing resume, prompt, create or fork.
346
+ retainPhase("external_dispatch_possible");
347
+ receipt = await runHarnessAdapter({ executable, args: settlementInspectArgs(args), harness: runtimeHarness(session.profile), env: controllerEnvironment(context, manifest, session), operationId, runtimeOwner: session.owner, timeoutMs, ...(signal ? { signal } : {}) });
348
+ }
349
+ else {
350
+ const observed = await recoverCompletedOperation(context, manifest, session, executable, args, operationId, signal);
351
+ if (!observed) {
352
+ const cause = existing.error_json ? JSON.parse(existing.error_json) : { code: "controller_operation_outcome_unknown", message: "Retained dispatch has no observed terminal result", details: { operation_id: operationId } };
353
+ throw new AppError(cause.code, cause.message, 1, cause.details);
354
+ }
355
+ receipt = observed;
356
+ recoveredOperation = true;
357
+ }
358
+ }
359
+ else {
360
+ // Keep observation/settlement of retained operations available after
361
+ // terminal RUN, but never admit fresh native productive dispatch.
362
+ const productive = ["daemon.start", "session.create", "session.start", "session.fork", "session.prompt", "session.resume"].includes(expectedMethod(args, session));
363
+ if (productive && ["done", "failed", "cancelled"].includes(requireRun(context, row.project_id, row.run_id).status))
364
+ throw new AppError("invalid_run_state", "A terminal RUN cannot admit a new native controller operation", 1);
365
+ retainPhase("external_dispatch_possible");
366
+ receipt = await runHarnessAdapter({ executable, args, harness: runtimeHarness(session.profile), env: controllerEnvironment(context, manifest, session), operationId, runtimeOwner: session.owner, timeoutMs, ...(signal ? { signal } : {}) });
367
+ }
368
+ }
369
+ catch (error) {
370
+ if (phase === "prepared" || phase === "receipt_observed" && existing?.receipt_json)
371
+ throw error;
372
+ const retained = await recoverCompletedOperation(context, manifest, session, executable, args, operationId, signal);
373
+ if (!retained)
374
+ throw error;
375
+ receipt = retained;
376
+ recoveredOperation = true;
377
+ }
378
+ validateReceipt(receipt, session, args);
379
+ const hookDiagnostics = Array.isArray(receipt.native_hook_diagnostics) ? receipt.native_hook_diagnostics : [];
380
+ if (hookDiagnostics.some(item => item && typeof item === "object" && ["native_hook_timeout", "native_hook_failed"].includes(String(item.code)))) {
381
+ recordTechnicalNote(context, row.project_id, row.run_id, { code: "native_hook_observation_unavailable",
382
+ message: "Native hook observation failed; the actual lifecycle command remains authoritative.", phase: "native_observation",
383
+ generation: row.generation, ...(effectiveObligation?.stage ? { stage: effectiveObligation.stage } : {}),
384
+ harness: runtimeHarness(session.profile), source_operation_id: operationId, resource_identity: session.state_dir,
385
+ diagnostic_reference: session.journal, consequence: "none" });
386
+ }
387
+ retainPhase("receipt_observed");
388
+ const persistReceipt = () => {
389
+ const changed = context.db.run("UPDATE run_controller_operations SET receipt_json = ?, updated_at = ? WHERE operation_id = ? AND controller_id = ? AND generation = ? AND EXISTS (SELECT 1 FROM run_controllers WHERE controller_id = ? AND owner_token = ? AND generation = ?)", [JSON.stringify(receipt), context.now(), operationId, row.controller_id, row.generation, row.controller_id, row.owner_token, row.generation]);
390
+ if (changed.changes !== 1)
391
+ throw new AppError("controller_owner_mismatch", "Controller lost ownership before receipt retention", 1);
392
+ };
393
+ persistReceipt();
394
+ if (["pending", "blocked"].includes(String(settlement(receipt)?.state)) && effectiveObligation && acceptedPromptBoundary(effectiveObligation)) {
395
+ // Required semantic work is already committed. Keep the honest pending
396
+ // native proof for resource cleanup without holding its accepted result.
397
+ recordTechnicalNote(context, row.project_id, row.run_id, { code: "accepted_boundary_native_settlement_pending", message: "The assigned result is committed; native settlement remains pending.", phase: "native_observation", generation: row.generation, stage: effectiveObligation.stage, harness: runtimeHarness(session.profile), source_operation_id: operationId, diagnostic_reference: session.state_dir, consequence: "cleanup_pending" });
398
+ receipt = { ...receipt, accepted_boundary: effectiveObligation };
399
+ }
400
+ else if (["pending", "blocked"].includes(String(settlement(receipt)?.state))) {
401
+ const recovered = await awaitSettlement(context, row, manifest, session, executable, args, operationId, receipt, assertOwner, signal);
402
+ receipt = recovered;
403
+ }
404
+ persistReceipt();
405
+ validateReceipt(receipt, session, args);
406
+ const completed = context.db.run("UPDATE run_controller_operations SET status = 'completed', updated_at = ? WHERE operation_id = ? AND controller_id = ? AND generation = ? AND EXISTS (SELECT 1 FROM run_controllers WHERE controller_id = ? AND owner_token = ? AND generation = ?)", [context.now(), operationId, row.controller_id, row.generation, row.controller_id, row.owner_token, row.generation]);
407
+ if (completed.changes !== 1)
408
+ throw new AppError("controller_owner_mismatch", "Controller lost ownership before operation completion", 1);
409
+ appendEvent(context, row.controller_id, recoveredOperation ? "operation_recovered" : "operation_completed", { operation_id: operationId, operation: args.slice(0, 2), session_id: adapterSessionId(receipt) });
410
+ return receipt;
411
+ }
412
+ catch (error) {
413
+ // A lost provider/transport acknowledgement cannot revoke the exact
414
+ // boundary already accepted by the engine. Identity/integrity failures
415
+ // and unfinished siblings remain on the existing recovery path.
416
+ const expected = effectiveObligation;
417
+ if (expected && lateNativeFailure(error, session.id) && acceptedPromptBoundary(expected)) {
418
+ assertOwner?.();
419
+ const receipt = { adapter_session_id: session.id, accepted_boundary: expected, native_observation_unavailable: true, settlement: { state: "pending", reason: "native_observation_unavailable" } };
420
+ const completed = context.db.run("UPDATE run_controller_operations SET status='completed',receipt_json=?,error_json=NULL,updated_at=? WHERE operation_id=? AND controller_id=? AND generation=? AND EXISTS (SELECT 1 FROM run_controllers WHERE controller_id=? AND owner_token=? AND generation=?)", [JSON.stringify(receipt), context.now(), operationId, row.controller_id, row.generation, row.controller_id, row.owner_token, row.generation]);
421
+ if (completed.changes !== 1)
422
+ throw new AppError("controller_owner_mismatch", "Controller lost ownership before accepting the committed boundary", 1);
423
+ recordTechnicalNote(context, row.project_id, row.run_id, { code: "accepted_boundary_native_observation_unavailable", message: "The assigned result is committed; the native acknowledgement is unavailable.", phase: "native_observation", generation: row.generation, stage: expected.stage, harness: runtimeHarness(session.profile), source_operation_id: operationId, diagnostic_reference: session.state_dir, consequence: "cleanup_pending" });
424
+ return receipt;
425
+ }
426
+ try {
427
+ context.db.run("UPDATE run_controller_operations SET status = CASE WHEN status = 'dispatching' AND ? <> 'prepared' THEN 'outcome_unknown' ELSE status END, error_json = ?, updated_at = ? WHERE operation_id = ? AND controller_id = ? AND generation = ? AND EXISTS (SELECT 1 FROM run_controllers WHERE controller_id = ? AND owner_token = ? AND generation = ?)", [phase ?? "legacy_unknown", JSON.stringify(errorRecord(error)), context.now(), operationId, row.controller_id, row.generation, row.controller_id, row.owner_token, row.generation]);
428
+ }
429
+ catch (persistence) {
430
+ process.stderr.write(`${JSON.stringify({ operation_id: operationId, primary: errorRecord(error), persistence_error: errorRecord(persistence) })}\n`);
431
+ }
432
+ throw error;
433
+ }
434
+ }
@@ -0,0 +1,186 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { setTimeout as delay } from "node:timers/promises";
4
+ import { AppError } from "../shared/errors.js";
5
+ import { createEvalRunSnapshot, verifyControllerBoundarySnapshot } from "./eval-snapshots.js";
6
+ import { observeControllerBoundary } from "./run-control.js";
7
+ import { assertRunMutationAllowed, recoveryGuard } from "./run-recovery.js";
8
+ import { appendEvent, digest, errorRecord, requireController, requireRun } from "./run-controller-state.js";
9
+ import { getFlowRunStatus, readFlowRunExecutionBundle } from "./runs.js";
10
+ import { recoveryObservationBudget, withRecoveryObservation } from "./recovery-observation-budget.js";
11
+ import { getResourceDatabase } from "../storage/database.js";
12
+ import { managedProcessBinding, resourceHome } from "./managed-processes.js";
13
+ /** Physical probes precede reservation; the accepted publisher still checks
14
+ * exact owner identity and fresh lease expiry after waiting for the writer. */
15
+ export function prepareControllerPublication(context, row, assertPhysicalOwner) {
16
+ assertPhysicalOwner();
17
+ const registry = getResourceDatabase(resourceHome(context));
18
+ const owner = registry.get("SELECT * FROM managed_processes WHERE id = ?", [row.process_id]);
19
+ if (!owner || owner.lease_token !== row.process_lease_token || owner.pid !== row.owner_pid || owner.owner_id !== row.controller_id)
20
+ throw new AppError("controller_owner_mismatch", "Controller publication lacks its physical owner", 1, { process_id: row.process_id, controller_id: row.controller_id, owner_found: Boolean(owner), lease_matches: owner?.lease_token === row.process_lease_token, pid_matches: owner?.pid === row.owner_pid, owner_matches: owner?.owner_id === row.controller_id, resource_home: resourceHome(context) });
21
+ const binding = managedProcessBinding(owner, resourceHome(context));
22
+ return () => {
23
+ const current = requireController(context, row.controller_id), process = registry.get("SELECT * FROM managed_processes WHERE id = ?", [owner.id]);
24
+ if (current.owner_token !== row.owner_token || current.owner_pid !== row.owner_pid || current.process_id !== row.process_id || current.process_lease_token !== row.process_lease_token || current.generation !== row.generation
25
+ || !["running", "capturing", "waiting_for_user", "waiting_for_context", "waiting_for_children", "waiting_for_capacity", "waiting_for_merge"].includes(current.status)
26
+ || !process || process.state !== "running" || process.lease_expires_at <= context.now() || digest(managedProcessBinding(process, resourceHome(context))) !== digest(binding))
27
+ throw new AppError("controller_owner_mismatch", "Controller publication lost its current physical lease", 1);
28
+ };
29
+ }
30
+ /** Capture is performed by the productive owner, before it releases the next
31
+ * Stage. An observer never races the controller to copy a completed boundary. */
32
+ export async function captureControllerBoundary(context, row, manifest, stage, nextStage, assertPhysicalOwner) {
33
+ const root = manifest.request.capture_root;
34
+ if (!root)
35
+ return;
36
+ const identity = (value) => ({ run_id: row.run_id, stage: value.stage, attempt: value.attempt ?? null, started_at: value.started_at ?? null, completed_at: value.completed_at ?? null });
37
+ const boundaryKey = digest(identity(stage));
38
+ const operationId = `${row.controller_id}:boundary:${boundaryKey}`;
39
+ const output = path.join(root, `${stage.stage}-${boundaryKey}`);
40
+ const scope = { projectRoot: manifest.request.project_root, runId: row.run_id };
41
+ const expected = { controllerId: row.controller_id, operationId, boundaryKey, runId: row.run_id, stageEntry: nextStage };
42
+ const prior = context.db.get("SELECT status,receipt_json FROM run_controller_operations WHERE operation_id = ?", [operationId]);
43
+ if (prior?.status === "completed") {
44
+ try {
45
+ const receipt = JSON.parse(prior.receipt_json ?? "{}");
46
+ if (typeof receipt.manifest_sha256 !== "string")
47
+ throw new AppError("controller_boundary_snapshot_invalid", "Completed capture has no immutable manifest receipt", 1);
48
+ verifyControllerBoundarySnapshot(output, { ...expected, manifestSha256: receipt.manifest_sha256 });
49
+ return;
50
+ }
51
+ catch (error) {
52
+ try {
53
+ assertPhysicalOwner();
54
+ context.db.run("UPDATE run_controllers SET status = 'capture_failed', last_error_json = ?, updated_at = ? WHERE controller_id = ? AND owner_token = ?", [JSON.stringify(errorRecord(error)), context.now(), row.controller_id, row.owner_token]);
55
+ }
56
+ catch (recordError) {
57
+ if (error instanceof AppError)
58
+ error.details.capture_error_recording = errorRecord(recordError);
59
+ }
60
+ throw error;
61
+ }
62
+ }
63
+ const preparedBundle = readFlowRunExecutionBundle(context, scope);
64
+ const assertStartOwner = prepareControllerPublication(context, row, assertPhysicalOwner);
65
+ context.db.writeTransaction(() => {
66
+ assertStartOwner();
67
+ assertRunMutationAllowed(context, row.project_id, row.run_id, row.generation);
68
+ const now = context.now();
69
+ context.db.run("UPDATE run_controllers SET status = 'capturing', updated_at = ? WHERE controller_id = ? AND owner_token = ?", [now, row.controller_id, row.owner_token]);
70
+ context.db.run("INSERT INTO run_controller_operations (operation_id,controller_id,generation,input_hash,input_json,status,created_at,updated_at) VALUES (?,?,?,?,?,'capturing',?,?) ON CONFLICT(operation_id) DO UPDATE SET generation = excluded.generation, status = 'capturing', error_json = NULL, updated_at = excluded.updated_at", [operationId, row.controller_id, row.generation, boundaryKey, JSON.stringify({ action: "boundary_capture", ...identity(stage), stage_entry: nextStage, output }), now, now]);
71
+ appendEvent(context, row.controller_id, "boundary_capture_requested", { operation_id: operationId, boundary_key: boundaryKey, stage: stage.stage, stage_entry: nextStage });
72
+ });
73
+ const assertCurrent = (physical = true) => {
74
+ if (physical)
75
+ assertPhysicalOwner();
76
+ const guard = recoveryGuard(context, row.project_id, row.run_id);
77
+ if ((guard?.generation ?? 0) !== row.generation || ["draining", "sealed", "resuming"].includes(guard?.status ?? ""))
78
+ throw new AppError("run_recovery_guarded", "Recovery or operator control superseded boundary capture", 1);
79
+ if (requireController(context, row.controller_id).status !== "capturing" || context.db.get("SELECT status FROM run_controller_operations WHERE operation_id = ?", [operationId])?.status !== "capturing")
80
+ throw new AppError("controller_capture_owner_lost", "Controller no longer owns boundary capture", 1);
81
+ const index = JSON.parse(requireRun(context, row.project_id, row.run_id).index_json);
82
+ const current = index.stage_runs.find(item => item.stage === stage.stage);
83
+ if (!current || !["done", "skipped"].includes(current.status) || digest(identity(current)) !== boundaryKey)
84
+ throw new AppError("controller_boundary_changed", "Stage identity changed after its capture fence", 1);
85
+ if (physical) {
86
+ const continuation = getFlowRunStatus(context, scope, preparedBundle ?? undefined).continuation;
87
+ const stoppedAtTarget = nextStage === null && manifest.request.stop_after === stage.stage && continuation.kind === "start_stage";
88
+ if (nextStage ? continuation.kind !== "start_stage" || continuation.stage !== nextStage : continuation.kind !== "terminal" && !stoppedAtTarget)
89
+ throw new AppError("controller_boundary_changed", "Stage successor changed after its capture fence", 1);
90
+ }
91
+ };
92
+ let priorObservation = null;
93
+ try {
94
+ priorObservation = prior?.receipt_json ? JSON.parse(prior.receipt_json) : null;
95
+ }
96
+ catch {
97
+ priorObservation = { recovery_observation: { remaining_ms: 0 } };
98
+ }
99
+ const observationBudget = recoveryObservationBudget(priorObservation);
100
+ try {
101
+ let receipt;
102
+ if (fs.existsSync(output)) {
103
+ assertCurrent();
104
+ receipt = verifyControllerBoundarySnapshot(output, expected);
105
+ }
106
+ else {
107
+ let lastPending = "";
108
+ let lastCaptureMismatch = null;
109
+ for (;;) {
110
+ assertCurrent();
111
+ if (fs.existsSync(output)) {
112
+ receipt = verifyControllerBoundarySnapshot(output, expected);
113
+ break;
114
+ }
115
+ if (observationBudget.exhausted()) {
116
+ assertCurrent();
117
+ if (fs.existsSync(output)) {
118
+ receipt = verifyControllerBoundarySnapshot(output, expected);
119
+ break;
120
+ }
121
+ context.db.run("UPDATE run_controller_operations SET receipt_json = json_set(json_set(COALESCE(receipt_json, '{}'), '$.recovery_observation', json(?)), '$.last_capture_mismatch', json(?)), updated_at = ? WHERE operation_id = ?", [JSON.stringify(observationBudget.state()), JSON.stringify(lastCaptureMismatch), context.now(), operationId]);
122
+ throw new AppError("recovery_observation_budget_exhausted", "Boundary capture has no stable settlement within the active observation budget", 1, { recovery_observation: observationBudget.state(), last_capture_mismatch: lastCaptureMismatch });
123
+ }
124
+ assertCurrent();
125
+ context.db.run("UPDATE run_controller_operations SET receipt_json = json_set(COALESCE(receipt_json, '{}'), '$.recovery_observation', json(?)), updated_at = ? WHERE operation_id = ?", [JSON.stringify(observationBudget.state()), context.now(), operationId]);
126
+ let verify = () => { throw new AppError("controller_boundary_unsettled", "Boundary has no stable writer observation", 1); };
127
+ const observation = await withRecoveryObservation(observationBudget, () => observeControllerBoundary(context, { ...scope, controllerId: row.controller_id, operationId, assertCurrent, retainVerification: value => {
128
+ verify = () => {
129
+ value();
130
+ if (readFlowRunExecutionBundle(context, scope)?.sha256 !== preparedBundle?.sha256)
131
+ throw new AppError("controller_boundary_changed", "Frozen bundle changed before snapshot publication", 1);
132
+ };
133
+ } }));
134
+ if (observation.settled === true) {
135
+ try {
136
+ createEvalRunSnapshot(context, { ...scope, output, ...(nextStage ? { stageEntry: nextStage } : { candidate: true }), boundary: { controllerId: row.controller_id, operationId, boundaryKey, observation, verify } });
137
+ receipt = verifyControllerBoundarySnapshot(output, expected);
138
+ break;
139
+ }
140
+ catch (error) {
141
+ if (!(error instanceof AppError) || !["snapshot_source_changed", "owned_inventory_changed"].includes(error.code))
142
+ throw error;
143
+ observation.settled = false;
144
+ observation.pending_reasons = [error.code];
145
+ lastCaptureMismatch = { code: error.code, components: error.details?.components ?? [], changes: error.details?.changes ?? [] };
146
+ }
147
+ }
148
+ observationBudget.observe(observation);
149
+ const published = { ...observation, recovery_observation: observationBudget.state(), last_capture_mismatch: lastCaptureMismatch };
150
+ const pending = digest(observation.pending_reasons);
151
+ context.db.run("UPDATE run_controller_operations SET receipt_json = ?, updated_at = ? WHERE operation_id = ?", [JSON.stringify(published), context.now(), operationId]);
152
+ if (pending !== lastPending) {
153
+ appendEvent(context, row.controller_id, "boundary_capture_pending", { operation_id: operationId, pending_reasons: observation.pending_reasons, last_capture_mismatch: lastCaptureMismatch });
154
+ lastPending = pending;
155
+ }
156
+ await delay(observationBudget.nextDelay());
157
+ }
158
+ }
159
+ assertCurrent();
160
+ const assertFinishOwner = prepareControllerPublication(context, row, assertPhysicalOwner);
161
+ const preparedIndex = requireRun(context, row.project_id, row.run_id).index_json;
162
+ context.db.writeTransaction(() => {
163
+ assertFinishOwner();
164
+ assertCurrent(false);
165
+ if (requireRun(context, row.project_id, row.run_id).index_json !== preparedIndex)
166
+ throw new AppError("controller_boundary_changed", "RUN changed before capture publication", 1);
167
+ context.db.run("UPDATE run_controller_operations SET status = 'completed', receipt_json = ?, error_json = NULL, updated_at = ? WHERE operation_id = ?", [JSON.stringify(receipt), context.now(), operationId]);
168
+ appendEvent(context, row.controller_id, "boundary_captured", { ...identity(stage), boundary_key: boundaryKey, operation_id: operationId, ...receipt });
169
+ context.db.run("UPDATE run_controllers SET status = 'running', updated_at = ? WHERE controller_id = ? AND owner_token = ?", [context.now(), row.controller_id, row.owner_token]);
170
+ });
171
+ }
172
+ catch (error) {
173
+ observationBudget.exhausted();
174
+ try {
175
+ context.db.writeTransaction(() => {
176
+ context.db.run("UPDATE run_controller_operations SET receipt_json = json_set(COALESCE(receipt_json, '{}'), '$.recovery_observation', json(?)) WHERE operation_id = ?", [JSON.stringify(observationBudget.state()), operationId]);
177
+ context.db.run("UPDATE run_controller_operations SET status = 'failed', error_json = ?, updated_at = ? WHERE operation_id = ?", [JSON.stringify(errorRecord(error)), context.now(), operationId]);
178
+ });
179
+ }
180
+ catch (recordError) {
181
+ if (error instanceof AppError)
182
+ error.details.capture_error_recording = errorRecord(recordError);
183
+ }
184
+ throw error;
185
+ }
186
+ }