@deksden-com/dd-flow-cli 0.9.0-beta.15 → 0.9.0-beta.151

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 (560) hide show
  1. package/CHANGELOG.md +907 -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 +386 -0
  6. package/dist/cli/command-metadata.js +232 -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/diagnostic-invocation.js +46 -0
  11. package/dist/cli/diagnostic.js +120 -0
  12. package/dist/cli/error-output.js +52 -0
  13. package/dist/cli/executor-onboarding.js +76 -0
  14. package/dist/cli/flows.js +29 -0
  15. package/dist/cli/harnesses.js +84 -0
  16. package/dist/cli/help.js +396 -19
  17. package/dist/cli/hook-ingress.js +102 -0
  18. package/dist/cli/input-preparation.js +165 -0
  19. package/dist/cli/memory-flow-admission.js +50 -0
  20. package/dist/cli/memory-init-invocation.js +85 -0
  21. package/dist/cli/memory-init.js +249 -0
  22. package/dist/cli/memory-storage-admission.js +54 -0
  23. package/dist/cli/memory-storage-qualification.js +105 -0
  24. package/dist/cli/memory-storage-transition.js +123 -0
  25. package/dist/cli/memory-upgrade.js +189 -0
  26. package/dist/cli/models.js +39 -0
  27. package/dist/cli/native-hook-ingress.js +90 -0
  28. package/dist/cli/native-hook-preparation.js +55 -0
  29. package/dist/cli/operator-profiles.js +61 -0
  30. package/dist/cli/output-options.js +35 -0
  31. package/dist/cli/response-file.js +72 -0
  32. package/dist/cli/run-cli.js +1734 -550
  33. package/dist/cli/runtime-maintenance-diagnostics.js +46 -0
  34. package/dist/cli/runtime-maintenance-ingress.js +52 -0
  35. package/dist/cli/runtime-process.js +153 -0
  36. package/dist/cli/setup.js +150 -0
  37. package/dist/cli.js +89 -2
  38. package/dist/domain/diagnostic-aspects.js +103 -0
  39. package/dist/domain/diagnostic-flows.js +8 -0
  40. package/dist/domain/stage-catalog.js +1 -1
  41. package/dist/domain/stage-handler-identities.js +28 -0
  42. package/dist/harness-runtime/DD-ZCODE.md +112 -0
  43. package/dist/harness-runtime/OPENCODE-LICENSE.txt +24 -0
  44. package/dist/harness-runtime/bin/dd-agy.mjs +56 -0
  45. package/dist/harness-runtime/bin/dd-codex.mjs +27 -0
  46. package/dist/harness-runtime/bin/dd-droid.mjs +34 -0
  47. package/dist/harness-runtime/bin/dd-grok.mjs +40 -0
  48. package/dist/harness-runtime/bin/dd-opencode.mjs +22 -0
  49. package/dist/harness-runtime/bin/dd-zcode.mjs +87 -0
  50. package/dist/harness-runtime/lib/adapter-timeouts.d.mts +5 -0
  51. package/dist/harness-runtime/lib/adapter-timeouts.mjs +34 -0
  52. package/dist/harness-runtime/lib/agy-error-boundary.mjs +79 -0
  53. package/dist/harness-runtime/lib/agy-hooks.d.mts +1 -0
  54. package/dist/harness-runtime/lib/agy-hooks.mjs +9 -0
  55. package/dist/harness-runtime/lib/agy-native-inspection.mjs +216 -0
  56. package/dist/harness-runtime/lib/agy-native_pb.js +117 -0
  57. package/dist/harness-runtime/lib/agy-terminal-envelope.mjs +67 -0
  58. package/dist/harness-runtime/lib/daemon-observation.d.mts +2 -0
  59. package/dist/harness-runtime/lib/daemon-observation.mjs +163 -0
  60. package/dist/harness-runtime/lib/daemon-operations.d.mts +2 -0
  61. package/dist/harness-runtime/lib/daemon-operations.mjs +462 -0
  62. package/dist/harness-runtime/lib/dd-agy-daemon.d.mts +6 -0
  63. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +1092 -0
  64. package/dist/harness-runtime/lib/dd-agy.mjs +86 -0
  65. package/dist/harness-runtime/lib/dd-codex-daemon.d.mts +1 -0
  66. package/dist/harness-runtime/lib/dd-codex-daemon.mjs +231 -0
  67. package/dist/harness-runtime/lib/dd-codex.d.mts +1 -0
  68. package/dist/harness-runtime/lib/dd-codex.mjs +954 -0
  69. package/dist/harness-runtime/lib/dd-droid-daemon.mjs +141 -0
  70. package/dist/harness-runtime/lib/dd-droid.mjs +626 -0
  71. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +555 -0
  72. package/dist/harness-runtime/lib/dd-grok.mjs +180 -0
  73. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +627 -0
  74. package/dist/harness-runtime/lib/dd-opencode.mjs +390 -0
  75. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +752 -0
  76. package/dist/harness-runtime/lib/dd-zcode.mjs +1200 -0
  77. package/dist/harness-runtime/lib/delegation-instructions.d.mts +14 -0
  78. package/dist/harness-runtime/lib/delegation-instructions.mjs +166 -0
  79. package/dist/harness-runtime/lib/dispatch-fence.mjs +14 -0
  80. package/dist/harness-runtime/lib/driver-recovery.mjs +140 -0
  81. package/dist/harness-runtime/lib/droid-observation.mjs +66 -0
  82. package/dist/harness-runtime/lib/entity-references.d.mts +2 -0
  83. package/dist/harness-runtime/lib/entity-references.mjs +9 -0
  84. package/dist/harness-runtime/lib/lease-renewal.d.mts +8 -0
  85. package/dist/harness-runtime/lib/lease-renewal.mjs +37 -0
  86. package/dist/harness-runtime/lib/lifecycle-command.d.mts +20 -0
  87. package/dist/harness-runtime/lib/lifecycle-command.mjs +273 -0
  88. package/dist/harness-runtime/lib/lifecycle-contract.d.mts +10 -0
  89. package/dist/harness-runtime/lib/lifecycle-contract.mjs +19 -0
  90. package/dist/harness-runtime/lib/managed-daemon.d.mts +16 -0
  91. package/dist/harness-runtime/lib/managed-daemon.mjs +698 -0
  92. package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
  93. package/dist/harness-runtime/lib/model-observations.mjs +113 -0
  94. package/dist/harness-runtime/lib/native-children.d.mts +34 -0
  95. package/dist/harness-runtime/lib/native-children.mjs +265 -0
  96. package/dist/harness-runtime/lib/native-hook-command.d.mts +7 -0
  97. package/dist/harness-runtime/lib/native-hook-command.mjs +251 -0
  98. package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
  99. package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
  100. package/dist/harness-runtime/lib/native-streams.mjs +45 -0
  101. package/dist/harness-runtime/lib/observation-clock.d.mts +18 -0
  102. package/dist/harness-runtime/lib/observation-clock.mjs +95 -0
  103. package/dist/harness-runtime/lib/opencode-plugin.mjs +85 -0
  104. package/dist/harness-runtime/lib/operation-context.mjs +5 -0
  105. package/dist/harness-runtime/lib/operation-errors.d.mts +16 -0
  106. package/dist/harness-runtime/lib/operation-errors.mjs +127 -0
  107. package/dist/harness-runtime/lib/operation-progress.d.mts +7 -0
  108. package/dist/harness-runtime/lib/operation-progress.mjs +114 -0
  109. package/dist/harness-runtime/lib/process-json.d.mts +5 -0
  110. package/dist/harness-runtime/lib/process-json.mjs +201 -0
  111. package/dist/harness-runtime/lib/process-snapshot.mjs +10 -0
  112. package/dist/harness-runtime/lib/provider-overload-policy.d.mts +23 -0
  113. package/dist/harness-runtime/lib/provider-overload-policy.mjs +242 -0
  114. package/dist/harness-runtime/lib/runner-events.mjs +202 -0
  115. package/dist/harness-runtime/lib/runner-lock.mjs +42 -0
  116. package/dist/harness-runtime/lib/session-settlement.mjs +30 -0
  117. package/dist/harness-runtime/lib/setup-progress.d.mts +9 -0
  118. package/dist/harness-runtime/lib/setup-progress.mjs +53 -0
  119. package/dist/harness-runtime/lib/tool-observations.d.mts +21 -0
  120. package/dist/harness-runtime/lib/tool-observations.mjs +228 -0
  121. package/dist/harness-runtime/lib/zcode-usage.mjs +55 -0
  122. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-1y4a697q.js +81 -0
  123. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-2ny4vxct.js +92 -0
  124. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-6mptkzbc.js +0 -0
  125. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-7x67cf1q.js +52 -0
  126. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9rqn6x4v.js +16 -0
  127. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9vdz0zwn.js +1661 -0
  128. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ecs5ftka.js +1466 -0
  129. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-frbwqjmf.js +145 -0
  130. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gne7h7mq.js +50 -0
  131. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gx9wnkzr.js +105 -0
  132. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-m2eywc8w.js +0 -0
  133. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-nwcpakzx.js +12 -0
  134. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-q4g3afnw.js +623 -0
  135. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-qav6mfdz.js +0 -0
  136. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-sxt88q69.js +12 -0
  137. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-t1xa31vm.js +39 -0
  138. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ve4aws36.js +103 -0
  139. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vmytr4q8.js +4 -0
  140. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vt9jbch8.js +36 -0
  141. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vyas3vgt.js +0 -0
  142. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-wjyeq25y.js +30 -0
  143. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-xgnj2w4v.js +20 -0
  144. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-y2etg5bs.js +9 -0
  145. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ydhz1zrh.js +238 -0
  146. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-z6qdwcsf.js +62 -0
  147. package/dist/harness-runtime/vendor/opencode-client/contract.d.ts +1 -0
  148. package/dist/harness-runtime/vendor/opencode-client/contract.js +12 -0
  149. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.d.ts +2806 -0
  150. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.js +0 -0
  151. package/dist/harness-runtime/vendor/opencode-client/effect/api.d.ts +4 -0
  152. package/dist/harness-runtime/vendor/opencode-client/effect/api.js +0 -0
  153. package/dist/harness-runtime/vendor/opencode-client/effect/client.d.ts +2530 -0
  154. package/dist/harness-runtime/vendor/opencode-client/effect/client.js +15 -0
  155. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.d.ts +7 -0
  156. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.js +6 -0
  157. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.d.ts +2529 -0
  158. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.js +8 -0
  159. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.d.ts +2 -0
  160. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.js +12 -0
  161. package/dist/harness-runtime/vendor/opencode-client/effect/index.d.ts +35 -0
  162. package/dist/harness-runtime/vendor/opencode-client/effect/index.js +75 -0
  163. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.d.ts +20 -0
  164. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.js +11 -0
  165. package/dist/harness-runtime/vendor/opencode-client/effect/service.d.ts +90 -0
  166. package/dist/harness-runtime/vendor/opencode-client/effect/service.js +187 -0
  167. package/dist/harness-runtime/vendor/opencode-client/package.json +84 -0
  168. package/dist/harness-runtime/vendor/opencode-client/promise/api.d.ts +21 -0
  169. package/dist/harness-runtime/vendor/opencode-client/promise/api.js +0 -0
  170. package/dist/harness-runtime/vendor/opencode-client/promise/client.d.ts +252 -0
  171. package/dist/harness-runtime/vendor/opencode-client/promise/client.js +14 -0
  172. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.d.ts +8 -0
  173. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.js +6 -0
  174. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.d.ts +259 -0
  175. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.js +7 -0
  176. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.d.ts +3 -0
  177. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.js +79 -0
  178. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.d.ts +8932 -0
  179. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.js +70 -0
  180. package/dist/harness-runtime/vendor/opencode-client/promise/index.d.ts +6 -0
  181. package/dist/harness-runtime/vendor/opencode-client/promise/index.js +83 -0
  182. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.d.ts +32 -0
  183. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.js +7 -0
  184. package/dist/harness-runtime/vendor/opencode-client/promise/service.d.ts +24 -0
  185. package/dist/harness-runtime/vendor/opencode-client/promise/service.js +187 -0
  186. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.d.ts +12 -0
  187. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.js +14 -0
  188. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.d.ts +20 -0
  189. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.js +14 -0
  190. package/dist/harness-runtime/vendor/opencode-client/service-contender.d.ts +37 -0
  191. package/dist/harness-runtime/vendor/opencode-client/service-contender.js +10 -0
  192. package/dist/harness-runtime/vendor/opencode-client/service-probe.d.ts +70 -0
  193. package/dist/harness-runtime/vendor/opencode-client/service-probe.js +16 -0
  194. package/dist/harness-runtime/vendor/opencode-client/service-timing.d.ts +12 -0
  195. package/dist/harness-runtime/vendor/opencode-client/service-timing.js +10 -0
  196. package/dist/harness-runtime/vendor/opencode-client/service-version.d.ts +2 -0
  197. package/dist/harness-runtime/vendor/opencode-client/service-version.js +6 -0
  198. package/dist/harness-runtime/vendor/opencode-client/service.d.ts +52 -0
  199. package/dist/harness-runtime/vendor/opencode-client/service.js +1 -0
  200. package/dist/harness-runtime/vendor/opencode-client/shared-events.d.ts +11 -0
  201. package/dist/harness-runtime/vendor/opencode-client/shared-events.js +8 -0
  202. package/dist/harness-runtime/vendor/opencode-client/solid/connection.d.ts +37 -0
  203. package/dist/harness-runtime/vendor/opencode-client/solid/connection.js +10 -0
  204. package/dist/harness-runtime/vendor/opencode-client/solid/data.d.ts +211 -0
  205. package/dist/harness-runtime/vendor/opencode-client/solid/data.js +18 -0
  206. package/dist/harness-runtime/vendor/opencode-client/solid/index.d.ts +3 -0
  207. package/dist/harness-runtime/vendor/opencode-client/solid/index.js +32 -0
  208. package/dist/harness-runtime/vendor/opencode-client/solid/pty.d.ts +22 -0
  209. package/dist/harness-runtime/vendor/opencode-client/solid/pty.js +8 -0
  210. package/dist/harness-runtime/vendor/opencode-plugin.mjs +3 -0
  211. package/dist/protocol/local-files.js +18 -9
  212. package/dist/runtime/context.js +8 -4
  213. package/dist/schemas/agent-profile.schema.json +1 -1
  214. package/dist/schemas/code-review-decision.schema.json +9 -0
  215. package/dist/schemas/code-review-result.schema.json +1 -1
  216. package/dist/schemas/code-verification.schema.json +7 -5
  217. package/dist/schemas/code-work-batch.schema.json +2 -2
  218. package/dist/schemas/diagnostic-stage-result.schema.json +354 -0
  219. package/dist/schemas/diagnostic-work-result.schema.json +296 -0
  220. package/dist/schemas/discovery-result.schema.json +184 -0
  221. package/dist/schemas/execution-bundle.schema.json +211 -0
  222. package/dist/schemas/execution-settings.schema.json +162 -0
  223. package/dist/schemas/flow-descriptor.schema.json +54 -0
  224. package/dist/schemas/flow-run.schema.json +29 -0
  225. package/dist/schemas/harness-catalog.schema.json +80 -0
  226. package/dist/schemas/mb-init-compose-result.schema.json +457 -0
  227. package/dist/schemas/mb-init-discover-result.schema.json +500 -0
  228. package/dist/schemas/mb-init-finish-result.schema.json +422 -0
  229. package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
  230. package/dist/schemas/mb-init-review-result.schema.json +396 -0
  231. package/dist/schemas/mb-init-verify-result.schema.json +391 -0
  232. package/dist/schemas/mb-upgrade-stage-result.schema.json +863 -0
  233. package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
  234. package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
  235. package/dist/schemas/memory-composition-work-result.schema.json +38 -0
  236. package/dist/schemas/memory-repair-work-result.schema.json +56 -0
  237. package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
  238. package/dist/schemas/memory-review-work-result.schema.json +43 -0
  239. package/dist/schemas/model-catalog.schema.json +153 -0
  240. package/dist/schemas/plan-review-decision.schema.json +12 -3
  241. package/dist/schemas/plan-review-result.schema.json +2 -2
  242. package/dist/schemas/profile-settings.schema.json +122 -0
  243. package/dist/schemas/project-flow-pack-manifest.schema.json +1 -1
  244. package/dist/schemas/release-impact.schema.json +3 -3
  245. package/dist/schemas/release-manifest.schema.json +291 -0
  246. package/dist/schemas/run-control-receipt.schema.json +118 -0
  247. package/dist/schemas/run-control-request.schema.json +36 -0
  248. package/dist/schemas/run-engine-binding.schema.json +1 -1
  249. package/dist/schemas/stage-start-response.schema.json +4 -0
  250. package/dist/schemas/vnext-protocol-plan.schema.json +2 -2
  251. package/dist/services/accepted-intent.js +139 -0
  252. package/dist/services/branch-context.js +3 -3
  253. package/dist/services/canon.js +54 -15
  254. package/dist/services/check-environment.js +21 -0
  255. package/dist/services/check-runner-evidence.js +277 -0
  256. package/dist/services/check-runner-proof.js +305 -0
  257. package/dist/services/cleanup.js +133 -40
  258. package/dist/services/cli-operation-classifier.js +26 -63
  259. package/dist/services/cli-upgrade-allowlist.js +27 -0
  260. package/dist/services/code-checks.js +1401 -119
  261. package/dist/services/codex-hook-delivery.js +32 -0
  262. package/dist/services/command-context.js +80 -0
  263. package/dist/services/compatibility-preflight.js +16 -3
  264. package/dist/services/config.js +11 -8
  265. package/dist/services/continuation-outcome.js +20 -0
  266. package/dist/services/controller-child-capacity.js +71 -0
  267. package/dist/services/controller-child-observer.js +121 -0
  268. package/dist/services/controller-execution.js +94 -0
  269. package/dist/services/controller-fanout.js +226 -0
  270. package/dist/services/controller-memory-task.js +45 -0
  271. package/dist/services/controller-memory-worker.js +49 -0
  272. package/dist/services/dashboard.js +143 -58
  273. package/dist/services/descriptor-coordinator-session.js +35 -0
  274. package/dist/services/descriptor-root-work.js +53 -0
  275. package/dist/services/descriptor-run-settlement.js +107 -0
  276. package/dist/services/descriptor-run-start.js +475 -0
  277. package/dist/services/descriptor-stage-coordinator.js +250 -0
  278. package/dist/services/descriptor-stage-settlement.js +223 -0
  279. package/dist/services/descriptor-stage-start.js +175 -0
  280. package/dist/services/diagnostic-evidence.js +73 -0
  281. package/dist/services/diagnostic-report-publication.js +72 -0
  282. package/dist/services/diagnostic-report.js +67 -0
  283. package/dist/services/diagnostic-run-bundle.js +74 -0
  284. package/dist/services/diagnostic-snapshot.js +159 -0
  285. package/dist/services/diagnostic-stage-handlers.js +108 -0
  286. package/dist/services/diagnostic-stage-results.js +132 -0
  287. package/dist/services/diagnostic-start.js +84 -0
  288. package/dist/services/diagnostic-work-batch.js +34 -0
  289. package/dist/services/diagnostic-work-collection.js +97 -0
  290. package/dist/services/diagnostic-work-registration.js +101 -0
  291. package/dist/services/diagnostic-work-results.js +93 -0
  292. package/dist/services/discovery/agy-discovery.js +2 -0
  293. package/dist/services/discovery/codex-discovery.js +2 -0
  294. package/dist/services/discovery/droid-discovery.js +2 -0
  295. package/dist/services/discovery/grok-discovery.js +2 -0
  296. package/dist/services/discovery/opencode-discovery.js +2 -0
  297. package/dist/services/discovery/static.js +31 -0
  298. package/dist/services/discovery/zcode-discovery.js +2 -0
  299. package/dist/services/engines.js +354 -163
  300. package/dist/services/eval-snapshots.js +1316 -150
  301. package/dist/services/execution-bundles.js +275 -0
  302. package/dist/services/execution-policy.js +185 -0
  303. package/dist/services/executor-onboarding.js +56 -0
  304. package/dist/services/external-work-launch.js +310 -0
  305. package/dist/services/flow-catalog.js +30 -0
  306. package/dist/services/flow-descriptors.js +82 -0
  307. package/dist/services/frozen-engine.js +387 -0
  308. package/dist/services/generic-execution.js +164 -0
  309. package/dist/services/harness-adapter.js +355 -36
  310. package/dist/services/harness-config.js +2 -0
  311. package/dist/services/harness-discovery.js +29 -0
  312. package/dist/services/harness-doctor.js +75 -0
  313. package/dist/services/harness-probe-effects.js +51 -0
  314. package/dist/services/harness-version-probe.js +100 -0
  315. package/dist/services/hook-memory-routing.js +188 -0
  316. package/dist/services/hook-recovery-guard.js +14 -0
  317. package/dist/services/hook-session-observation.js +24 -0
  318. package/dist/services/hooks.js +791 -326
  319. package/dist/services/hybrid-contracts.js +474 -0
  320. package/dist/services/hybrid-digest.js +14 -0
  321. package/dist/services/ids.js +29 -1
  322. package/dist/services/installation-lock.js +95 -0
  323. package/dist/services/installed-flow-source.js +226 -0
  324. package/dist/services/lanes.js +78 -65
  325. package/dist/services/lifecycle-command.js +1 -288
  326. package/dist/services/lifecycle-contract.js +1 -0
  327. package/dist/services/lifecycle-invocations.js +2148 -0
  328. package/dist/services/managed-daemon-binding.js +38 -0
  329. package/dist/services/managed-lease-monitor.js +133 -0
  330. package/dist/services/managed-processes.js +449 -69
  331. package/dist/services/memory-accepted-composition.js +78 -0
  332. package/dist/services/memory-baseline-preservation.js +65 -0
  333. package/dist/services/memory-completed-correction-wave.js +328 -0
  334. package/dist/services/memory-compose-handler.js +400 -0
  335. package/dist/services/memory-composition-acceptance.js +375 -0
  336. package/dist/services/memory-composition-graph.js +165 -0
  337. package/dist/services/memory-composition-registration.js +161 -0
  338. package/dist/services/memory-composition-work-custody.js +156 -0
  339. package/dist/services/memory-composition-work-results.js +108 -0
  340. package/dist/services/memory-corrected-review-acceptance.js +129 -0
  341. package/dist/services/memory-corrected-review-batch.js +37 -0
  342. package/dist/services/memory-corrected-review-findings.js +108 -0
  343. package/dist/services/memory-corrected-review-inputs.js +215 -0
  344. package/dist/services/memory-corrected-review-projection.js +78 -0
  345. package/dist/services/memory-corrected-review-receipt.js +178 -0
  346. package/dist/services/memory-corrected-review-registration.js +192 -0
  347. package/dist/services/memory-correction-check-receipt.js +235 -0
  348. package/dist/services/memory-correction-input-owner.js +6 -0
  349. package/dist/services/memory-custody-snapshot.js +36 -0
  350. package/dist/services/memory-discover-handler.js +104 -0
  351. package/dist/services/memory-finish-evidence.js +457 -0
  352. package/dist/services/memory-finish-handler.js +229 -0
  353. package/dist/services/memory-finish-integration.js +450 -0
  354. package/dist/services/memory-finish-readiness.js +169 -0
  355. package/dist/services/memory-git-integration.js +220 -0
  356. package/dist/services/memory-historical-corrected-review.js +212 -0
  357. package/dist/services/memory-historical-original-review.js +143 -0
  358. package/dist/services/memory-historical-repair-registration.js +105 -0
  359. package/dist/services/memory-historical-second-review.js +147 -0
  360. package/dist/services/memory-init-bootstrap-readiness.js +210 -0
  361. package/dist/services/memory-init-contexts.js +131 -0
  362. package/dist/services/memory-init-controller-start.js +103 -0
  363. package/dist/services/memory-init-engine-release.js +223 -0
  364. package/dist/services/memory-init-git-policy.js +165 -0
  365. package/dist/services/memory-init-lint-capability.js +203 -0
  366. package/dist/services/memory-init-native-capacity.js +309 -0
  367. package/dist/services/memory-init-preflight.js +334 -0
  368. package/dist/services/memory-init-project-bootstrap.js +599 -0
  369. package/dist/services/memory-init-request-candidate.js +213 -0
  370. package/dist/services/memory-init-request-input.js +82 -0
  371. package/dist/services/memory-init-resource-storage.js +125 -0
  372. package/dist/services/memory-init-run-allocation.js +81 -0
  373. package/dist/services/memory-init-run-bundle.js +135 -0
  374. package/dist/services/memory-init-start.js +181 -0
  375. package/dist/services/memory-init-startup-custody.js +80 -0
  376. package/dist/services/memory-init-startup-input.js +240 -0
  377. package/dist/services/memory-init-storage.js +91 -0
  378. package/dist/services/memory-init-stores.js +359 -0
  379. package/dist/services/memory-init-worktrunk-capability.js +174 -0
  380. package/dist/services/memory-layer-publication.js +611 -0
  381. package/dist/services/memory-layer.js +221 -0
  382. package/dist/services/memory-lint-config.js +194 -0
  383. package/dist/services/memory-native-review-copy.js +103 -0
  384. package/dist/services/memory-normal-flow-entry.js +87 -0
  385. package/dist/services/memory-ordinary-defaults.js +129 -0
  386. package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
  387. package/dist/services/memory-preflight-handler.js +274 -0
  388. package/dist/services/memory-repair-current-view.js +299 -0
  389. package/dist/services/memory-repair-document-delta.js +488 -0
  390. package/dist/services/memory-repair-history.js +496 -0
  391. package/dist/services/memory-repair-physical-binding.js +194 -0
  392. package/dist/services/memory-repair-publication-files.js +152 -0
  393. package/dist/services/memory-repair-publication-intent.js +27 -0
  394. package/dist/services/memory-repair-publication-plan.js +162 -0
  395. package/dist/services/memory-repair-publication-source.js +225 -0
  396. package/dist/services/memory-repair-publication.js +795 -0
  397. package/dist/services/memory-repair-registration.js +240 -0
  398. package/dist/services/memory-repair-work-baseline.js +415 -0
  399. package/dist/services/memory-repair-work-completion.js +117 -0
  400. package/dist/services/memory-repair-work-custody.js +73 -0
  401. package/dist/services/memory-repair-work-results.js +108 -0
  402. package/dist/services/memory-repair-workspace.js +261 -0
  403. package/dist/services/memory-repair-writer-copy.js +736 -0
  404. package/dist/services/memory-result-binding.js +239 -0
  405. package/dist/services/memory-retained-review-authority.js +138 -0
  406. package/dist/services/memory-retained-review-results.js +70 -0
  407. package/dist/services/memory-retained-second-baseline.js +102 -0
  408. package/dist/services/memory-retained-second-repairs.js +162 -0
  409. package/dist/services/memory-review-acceptance.js +214 -0
  410. package/dist/services/memory-review-correction-plan.js +206 -0
  411. package/dist/services/memory-review-handler.js +585 -0
  412. package/dist/services/memory-review-inputs.js +246 -0
  413. package/dist/services/memory-review-limits.js +10 -0
  414. package/dist/services/memory-review-receipt.js +180 -0
  415. package/dist/services/memory-review-registration.js +117 -0
  416. package/dist/services/memory-review-work-custody.js +126 -0
  417. package/dist/services/memory-review-work-input.js +91 -0
  418. package/dist/services/memory-review-work-results.js +95 -0
  419. package/dist/services/memory-second-corrected-review-inputs.js +167 -0
  420. package/dist/services/memory-second-correction-plan.js +77 -0
  421. package/dist/services/memory-second-repair-baseline.js +91 -0
  422. package/dist/services/memory-second-repair-launch.js +614 -0
  423. package/dist/services/memory-second-repair-registration.js +88 -0
  424. package/dist/services/memory-second-repair-source.js +187 -0
  425. package/dist/services/memory-second-review-acceptance.js +115 -0
  426. package/dist/services/memory-source-observations.js +117 -0
  427. package/dist/services/memory-stage-dispatch.js +65 -0
  428. package/dist/services/memory-stage-results.js +290 -0
  429. package/dist/services/memory-tool-probe.js +25 -0
  430. package/dist/services/memory-upgrade-analysis-handler.js +243 -0
  431. package/dist/services/memory-upgrade-bootstrap-readiness.js +251 -0
  432. package/dist/services/memory-upgrade-evidence.js +100 -0
  433. package/dist/services/memory-upgrade-inventory.js +442 -0
  434. package/dist/services/memory-upgrade-publication-custody.js +73 -0
  435. package/dist/services/memory-upgrade-publication.js +413 -0
  436. package/dist/services/memory-upgrade-selection.js +430 -0
  437. package/dist/services/memory-upgrade-start.js +60 -0
  438. package/dist/services/memory-upgrade-storage-readiness.js +340 -0
  439. package/dist/services/memory-verification-acceptance.js +156 -0
  440. package/dist/services/memory-verification-checks.js +317 -0
  441. package/dist/services/memory-verification-receipt.js +160 -0
  442. package/dist/services/memory-verify-handler.js +137 -0
  443. package/dist/services/memory-work-result-json.js +12 -0
  444. package/dist/services/memory-work-result-preparation.js +64 -0
  445. package/dist/services/merge-queue.js +228 -149
  446. package/dist/services/merge-server.js +163 -35
  447. package/dist/services/migrations.js +164 -114
  448. package/dist/services/model-catalog.js +109 -0
  449. package/dist/services/model-discovery.js +46 -0
  450. package/dist/services/native-daemon-history.js +50 -0
  451. package/dist/services/native-session-control.js +39 -0
  452. package/dist/services/operator-profiles.js +236 -0
  453. package/dist/services/physical-startup.js +45 -0
  454. package/dist/services/plan-runtime.js +26 -11
  455. package/dist/services/plans.js +28 -25
  456. package/dist/services/project-registry.js +97 -0
  457. package/dist/services/project-summary.js +1 -1
  458. package/dist/services/projects.js +17 -87
  459. package/dist/services/prompt-delivery.js +71 -0
  460. package/dist/services/prompts.js +28 -17
  461. package/dist/services/protocols.js +163 -87
  462. package/dist/services/provider-capacity.js +463 -0
  463. package/dist/services/recovery-observation-budget.js +121 -0
  464. package/dist/services/recovery-snapshot-database.js +588 -0
  465. package/dist/services/release-archive-producer.js +52 -0
  466. package/dist/services/release-archive.js +143 -0
  467. package/dist/services/release-cache.js +150 -0
  468. package/dist/services/release-compatibility.js +18 -0
  469. package/dist/services/release-download.js +67 -0
  470. package/dist/services/release-envelope.js +104 -0
  471. package/dist/services/release-manifest.js +45 -0
  472. package/dist/services/release-payload.js +114 -0
  473. package/dist/services/release-producer.js +63 -0
  474. package/dist/services/release-provenance.js +160 -0
  475. package/dist/services/release-registry.js +66 -0
  476. package/dist/services/release-source.js +194 -0
  477. package/dist/services/repair-intents.js +31 -0
  478. package/dist/services/repair-receipt.js +13 -0
  479. package/dist/services/review-copy.js +165 -0
  480. package/dist/services/review-deferral.js +23 -0
  481. package/dist/services/run-control-receipt.js +56 -0
  482. package/dist/services/run-control-worker.js +428 -0
  483. package/dist/services/run-control.js +1092 -0
  484. package/dist/services/run-controller-adapter.js +400 -0
  485. package/dist/services/run-controller-capture.js +186 -0
  486. package/dist/services/run-controller-process.js +205 -0
  487. package/dist/services/run-controller-recovery.js +295 -0
  488. package/dist/services/run-controller-state.js +97 -0
  489. package/dist/services/run-controller.js +1395 -0
  490. package/dist/services/run-engine-bindings.js +1 -1
  491. package/dist/services/run-fork.js +147 -0
  492. package/dist/services/run-health.js +149 -0
  493. package/dist/services/run-observations.js +152 -0
  494. package/dist/services/run-projection.js +22 -64
  495. package/dist/services/run-recovery-guard.js +107 -0
  496. package/dist/services/run-recovery-runtime.js +112 -0
  497. package/dist/services/run-recovery.js +456 -0
  498. package/dist/services/run-start-custody.js +189 -0
  499. package/dist/services/runs.js +1023 -246
  500. package/dist/services/runtime-budget.js +446 -0
  501. package/dist/services/runtime-command.js +43 -0
  502. package/dist/services/runtime-scope-capture.js +52 -0
  503. package/dist/services/runtime-scope-control.js +468 -0
  504. package/dist/services/runtime-scope-resume.js +605 -0
  505. package/dist/services/runtime-scope-stop.js +211 -0
  506. package/dist/services/runtime-scope-worker.js +314 -0
  507. package/dist/services/runtime-service.js +19 -14
  508. package/dist/services/schema-validation.js +10 -8
  509. package/dist/services/scope-writer-cleanup.js +27 -0
  510. package/dist/services/sessions.js +36 -91
  511. package/dist/services/setup.js +427 -0
  512. package/dist/services/stage-blocker.js +17 -7
  513. package/dist/services/stage-context.js +240 -18
  514. package/dist/services/stage-handlers.js +89 -0
  515. package/dist/services/stage-lifecycle.js +152 -116
  516. package/dist/services/stage-pause.js +202 -91
  517. package/dist/services/stage-report-renderer.js +234 -6
  518. package/dist/services/stage-work-graph.js +52 -0
  519. package/dist/services/tooling.js +41 -30
  520. package/dist/services/usage.js +49 -101
  521. package/dist/services/verification-matrix.js +393 -0
  522. package/dist/services/version-status.js +1 -1
  523. package/dist/services/vnext-code-review.js +235 -88
  524. package/dist/services/vnext-code.js +327 -226
  525. package/dist/services/vnext-contracts.js +10 -1
  526. package/dist/services/vnext-execution-profile.js +80 -5
  527. package/dist/services/vnext-fanout.js +355 -21
  528. package/dist/services/vnext-merge.js +332 -111
  529. package/dist/services/vnext-plan-review.js +287 -132
  530. package/dist/services/vnext-plan.js +228 -104
  531. package/dist/services/vnext-protocolize.js +533 -95
  532. package/dist/services/vnext-specify.js +123 -81
  533. package/dist/services/vnext-workspace-policy.js +7 -2
  534. package/dist/services/work-registry.js +1706 -200
  535. package/dist/services/workspace-bootstrap.js +53 -15
  536. package/dist/services/workspace-files.js +85 -0
  537. package/dist/services/worktrees.js +105 -48
  538. package/dist/shared/entity-references.js +1 -0
  539. package/dist/shared/errors.js +27 -0
  540. package/dist/storage/agent-output.js +26 -0
  541. package/dist/storage/data-preservation.js +65 -0
  542. package/dist/storage/database.js +930 -40
  543. package/dist/storage/foreign-key-transaction.js +39 -0
  544. package/dist/storage/immutable-input.js +45 -0
  545. package/dist/storage/import-guard.js +159 -0
  546. package/dist/storage/memory-upgrade-schema-bootstrap.js +38 -0
  547. package/dist/storage/native-cleanup.js +52 -0
  548. package/dist/storage/paired-writer-migration.js +424 -0
  549. package/dist/storage/paths.js +17 -4
  550. package/dist/storage/projection-lock.js +73 -0
  551. package/dist/storage/work-references.js +23 -0
  552. package/dist/storage/writer-contract.js +96 -0
  553. package/dist/storage/writer-migration.js +346 -0
  554. package/dist/storage/writer-restore.js +217 -0
  555. package/dist/verification-components.json +299 -0
  556. package/package.json +51 -13
  557. package/tools/create-canon-release.mjs +33 -0
  558. package/tools/probe-codex-history.mjs +37 -0
  559. package/tools/produce-hybrid-release.mjs +41 -0
  560. package/tools/repair-paused-run-status.mjs +84 -0
@@ -0,0 +1,462 @@
1
+ import { createHash } from "node:crypto";
2
+ import { lstatSync } from "node:fs";
3
+ import { mkdir, readFile, readdir, link, unlink, open } from "node:fs/promises";
4
+ import { randomUUID } from "node:crypto";
5
+ import path from "node:path";
6
+ import { hashJson, writeJsonAtomic } from "./runner-events.mjs";
7
+ import { errorRecord, isObservationLoss, isProvenShellCorrection, reportedError } from "./operation-errors.mjs";
8
+ import { assertDaemonOwnership, budgetObservationScope, releaseBudgetObservation, completeBudgetOperation, stopProcessGroup } from "./managed-daemon.mjs";
9
+ import { processSnapshot } from "./process-snapshot.mjs";
10
+ import { NATIVE_SHUTDOWN_CONTRACT, NATIVE_SHUTDOWN_PHASES } from "./native-children.mjs";
11
+ import { readModelObservations, modelAttribution } from "./model-observations.mjs";
12
+ import { publishOperationProgress, publishOperationWaiting, withOperationProgress } from './operation-progress.mjs';
13
+ import { prepareDaemonRequest } from "./native-request-proof.mjs";
14
+
15
+ const productive = new Set(["session.create", "session.prompt", "session.start", "session.fork", "session.resume"]);
16
+ const controls = new Map();
17
+ const dispatchGenerations = new Map();
18
+ const shutdowns = new Map();
19
+ const settlements = new Map();
20
+
21
+ // Configuration locations only: credentials and arbitrary process env are not
22
+ // replay inputs. The browser cache is additive for historical five-key launches.
23
+ const nativeLaunchEnvironmentKeys = ["CODEX_HOME", "DD_FLOW_CONFIG_HOME", "DD_FLOW_HOME", "DD_FLOW_BIN", "DD_FLOW_RESOURCE_HOME"];
24
+ export function validateNativeLaunchEnvironment(value) {
25
+ const cache = value?.PLAYWRIGHT_BROWSERS_PATH;
26
+ if (!value || typeof value !== "object" || Array.isArray(value)
27
+ || Object.keys(value).some(key => ![...nativeLaunchEnvironmentKeys, "PLAYWRIGHT_BROWSERS_PATH"].includes(key))
28
+ || nativeLaunchEnvironmentKeys.some(key => value[key] !== null && typeof value[key] !== "string")
29
+ || Object.hasOwn(value, "PLAYWRIGHT_BROWSERS_PATH") && cache !== null
30
+ && (typeof cache !== "string" || !cache || cache.length > 4096 || cache.includes("\0") || !path.isAbsolute(cache)))
31
+ throw Object.assign(new Error("Native launch requires explicit configuration locations and an absolute browser cache"), { code: "runtime_scope_native_launch_required" });
32
+ return value;
33
+ }
34
+
35
+ // Progress is not outcome authority. Once native effect is retained, a failed
36
+ // diagnostic write must keep its identity and prohibit redispatch.
37
+ async function publishRetainedProgress(root, id, phase, result, metadata) {
38
+ try { return await publishOperationProgress(root, id, phase, metadata); }
39
+ catch (cause) {
40
+ throw Object.assign(new Error('native outcome retained but operation progress could not be published'), {
41
+ code: 'operation_observation_lost', retryable: false, cause,
42
+ details: { operation_id: id, state_dir: root, native_outcome: 'completed', native_result: result, progress_error: errorRecord(cause) }
43
+ });
44
+ }
45
+ }
46
+
47
+ export function assertDaemonDispatch(root) {
48
+ const stop = shutdowns.get(root);
49
+ if (stop?.pending || stop?.committed) throw Object.assign(new Error("daemon shutdown fences productive dispatch"), { code: "daemon_stopping" });
50
+ }
51
+ export function assertDaemonRestartable(state) {
52
+ if (["unclean", "cleanup_failed", "stopping"].includes(state?.shutdown_state)) throw Object.assign(new Error("previous daemon shutdown is unresolved; do not restart a native bridge for cleanup"), { code: "daemon_state_terminal", details: { daemon_id: state.daemon_id ?? state.config?.daemonId, shutdown_state: state.shutdown_state } });
53
+ }
54
+ export function commitDaemonShutdown(root) {
55
+ if (typeof root !== 'string') return; // In-memory adapter diagnostics own no daemon endpoint.
56
+ const fence = shutdowns.get(root) ?? { pending: 0 };
57
+ fence.committed = true; shutdowns.set(root, fence);
58
+ }
59
+
60
+ function ownedSnapshot(snapshot, rootPid) {
61
+ const owned = new Set([rootPid]); let size;
62
+ do { size = owned.size; for (const item of snapshot) if (owned.has(item.ppid)) owned.add(item.pid); } while (size !== owned.size);
63
+ return snapshot.filter(item => item.pid !== rootPid && owned.has(item.pid) && !item.zombie);
64
+ }
65
+ const mergeProcesses = (...snapshots) => [...new Map(snapshots.flat().map(item => [`${item.pid}:${item.started}`, item])).values()];
66
+
67
+ /** The same incarnation may retry remaining cleanup, never a native Turn. */
68
+ export async function completeDaemonShutdown(root, state, persist, prepare, phases, reconcileResources) {
69
+ const daemonId = state.daemon_id ?? state.config?.daemonId;
70
+ let shutdown = state.shutdown;
71
+ if (shutdown && shutdown.schema_id !== NATIVE_SHUTDOWN_CONTRACT) throw Object.assign(new Error("shutdown contract mismatch; retain historical owner evidence"), { code: "native_contract_mismatch" });
72
+ if (!shutdown || shutdown.daemon_id !== daemonId) shutdown = { schema_id: NATIVE_SHUTDOWN_CONTRACT, daemon_id: daemonId, generation: dispatchGenerations.get(root) ?? 0, phases: {} };
73
+ shutdown = { ...shutdown, required_phases: [...new Set([...NATIVE_SHUTDOWN_PHASES, ...phases.map(([phase]) => phase)])] };
74
+ try {
75
+ if (!shutdown.phases.execution) {
76
+ // Some native adapters close their provider inside prepare(). Observe
77
+ // ownership first, before that close can reparent a support process.
78
+ const before = ownedSnapshot(await processSnapshot(), state.pid);
79
+ shutdown = { ...shutdown, generation: dispatchGenerations.get(root) ?? shutdown.generation,
80
+ owned_processes: mergeProcesses(shutdown.owned_processes ?? [], before), inventory_complete: state.pid === process.pid };
81
+ await persist({ shutdown });
82
+ const result = await prepare();
83
+ commitDaemonShutdown(root);
84
+ // Compute ancestry within each snapshot, not across recycled parent PIDs.
85
+ const resources = mergeProcesses(shutdown.owned_processes, ownedSnapshot(await processSnapshot(), state.pid));
86
+ shutdown = { ...shutdown, phases: { execution: true }, owned_processes: resources,
87
+ inventory_complete: state.pid === process.pid, tree_observed_at: new Date().toISOString(), preparation_clean: result?.clean !== false, result: result ?? {} };
88
+ await persist({ shutdown, shutdown_state: "stopping" });
89
+ }
90
+ commitDaemonShutdown(root);
91
+ if (reconcileResources && !shutdown.phases.owned_resources) {
92
+ const revision = state.native_execution_revision, generation = dispatchGenerations.get(root) ?? shutdown.generation;
93
+ const resources = await reconcileResources();
94
+ const prior = shutdown.result?.native_resources;
95
+ if ((state.daemon_id ?? state.config?.daemonId) !== daemonId || state.native_execution_revision !== revision
96
+ || (dispatchGenerations.get(root) ?? shutdown.generation) !== generation || state.active_tree !== false || state.unclaimed_activity
97
+ || !resources || resources.schema_id !== 'native-resources@1' || resources.owner_daemon_id !== daemonId
98
+ || resources.generation !== prior?.generation || resources.revision !== prior?.revision || !Array.isArray(resources.entries)
99
+ || resources.entries.some(item => item.owner_daemon_id !== daemonId || item.generation !== resources.generation))
100
+ throw Object.assign(new Error('native resource reconciliation lost its owner/execution fence'), { code: 'native_resources_unproven' });
101
+ shutdown = { ...shutdown, result: { ...shutdown.result, native_resources: resources } };
102
+ await persist({ shutdown });
103
+ }
104
+ for (const [phase, action] of phases) {
105
+ if (phase === "daemon_resource" && !shutdown.phases.owned_resources) {
106
+ if (!shutdown.inventory_complete) throw Object.assign(new Error("owned resource coverage is unknown"), { code: "native_resources_unproven" });
107
+ for (const retained of shutdown.owned_processes ?? []) {
108
+ const current = (await processSnapshot()).find(item => item.pid === retained.pid);
109
+ if (!current || current.started !== retained.started || current.zombie) continue;
110
+ await stopProcessGroup({ pid: retained.pid, started: retained.started }, 1000, { detached: false });
111
+ }
112
+ const remaining = await processSnapshot();
113
+ if ((shutdown.owned_processes ?? []).some(retained => remaining.some(item => item.pid === retained.pid && item.started === retained.started && !item.zombie))) throw Object.assign(new Error("owned resources remain live"), { code: "native_resources_unproven" });
114
+ const nativeResources = shutdown.result?.native_resources;
115
+ const resourceGap = nativeResources?.entries?.some(resource => resource.observation_conflict === true || resource.state !== "stopped"
116
+ && !(resource.classification === "required_work" && shutdown.result?.native_settled === true && shutdown.result?.settled === true)
117
+ && !(shutdown.owned_processes ?? []).some(item => resource.pid === item.pid && resource.started === item.started));
118
+ shutdown = { ...shutdown, phases: { ...shutdown.phases, owned_resources: !resourceGap },
119
+ resource_retirement: { confirmed: !resourceGap, reason: resourceGap ? "native_resource_identity_unproven" : "owned_processes_retired" } };
120
+ await persist({ shutdown });
121
+ // Keep the technical cleanup owner/endpoint available for a later
122
+ // read-only reconciliation. Retiring its lease here would make the
123
+ // actual daemon exit before the retained resources can converge.
124
+ if (resourceGap) throw Object.assign(new Error("native resource retirement remains unproven"), { code: "native_resources_unproven" });
125
+ }
126
+ if (shutdown.phases[phase]) continue;
127
+ await action();
128
+ shutdown = { ...shutdown, phases: { ...shutdown.phases, [phase]: true } };
129
+ await persist({ shutdown });
130
+ }
131
+ const publishedRevision = state.native_execution_revision;
132
+ const sameRevision = publishedRevision === undefined || publishedRevision === shutdown.result?.native_settlement?.revision;
133
+ const nativeSettled = sameRevision && state.active_tree === false && !state.unclaimed_activity && shutdown.result?.settled === true && shutdown.result?.native_settled === true && shutdown.result?.native_settlement?.confirmed !== false;
134
+ const physicalStopped = shutdown.required_phases.every(phase => shutdown.phases[phase] === true);
135
+ // Cleanup retries/joining controls advance the control fence, not the old
136
+ // native Turn. Publish the current control generation with retained phases.
137
+ shutdown = { ...shutdown, generation: dispatchGenerations.get(root) ?? shutdown.generation };
138
+ const { result: ignored, ...proof } = shutdown; void ignored;
139
+ let result = { ...shutdown.result, daemon_id: daemonId, stopped: true, physical_stopped: physicalStopped,
140
+ settled: nativeSettled, native_settled: nativeSettled, clean: (shutdown.preparation_clean ?? shutdown.result?.clean !== false) && nativeSettled && physicalStopped,
141
+ resource_retirement: shutdown.resource_retirement,
142
+ shutdown_contract: NATIVE_SHUTDOWN_CONTRACT, shutdown_proof: proof, _shutdown: true };
143
+ shutdown = { ...shutdown, result };
144
+ // prepare() owns execution quiescence. A stale publication must not clear
145
+ // activity that arrives while its durable write is in flight.
146
+ await persist({ shutdown, shutdown_state: result.clean === true ? "clean" : "unclean", stopped_at: new Date().toISOString(), cleanup_error: null });
147
+ if (nativeSettled && (state.native_execution_revision !== publishedRevision || state.active_tree !== false || state.unclaimed_activity)) {
148
+ shutdown = { ...shutdown, phases: { ...shutdown.phases, execution: false } };
149
+ result = { ...result, clean: false, settled: false, native_settled: false,
150
+ native_settlement: { ...result.native_settlement, confirmed: false, reason: "late_activity_during_shutdown_publication" },
151
+ shutdown_proof: { ...proof, phases: shutdown.phases } };
152
+ shutdown = { ...shutdown, result };
153
+ await persist({ shutdown, shutdown_state: "unclean" });
154
+ }
155
+ return result;
156
+ } catch (error) {
157
+ if (error.code === "tree_not_settled" && !shutdowns.get(root)?.committed) throw error;
158
+ try { await persist({ shutdown_state: "cleanup_failed", cleanup_error: errorRecord(error) }); }
159
+ catch (storage) { error.details = { ...error.details, persistence_error: errorRecord(storage) }; }
160
+ throw error;
161
+ }
162
+ }
163
+
164
+ const daemonConnections = new WeakMap();
165
+ export function trackDaemonConnections(server) {
166
+ const sockets = new Set(); daemonConnections.set(server, sockets);
167
+ server.once("listening", () => {
168
+ const endpoint = server.address();
169
+ if (typeof endpoint !== "string") return;
170
+ try { const info = lstatSync(endpoint); daemonEndpoints.set(server, { endpoint, dev: info.dev, ino: info.ino }); }
171
+ catch (error) { daemonEndpoints.set(server, { endpoint, error }); }
172
+ });
173
+ server.on("connection", socket => { sockets.add(socket); socket.on("error", () => {}); socket.once("close", () => sockets.delete(socket)); });
174
+ }
175
+ const daemonEndpoints = new WeakMap();
176
+
177
+ /** Retire the listener after durable publication, before ACK; no provider IO. */
178
+ export function retireDaemonEndpoint(server, exitCode = 0) {
179
+ if (!server.listening) return;
180
+ const retained = daemonEndpoints.get(server);
181
+ let endpointError = retained?.error;
182
+ if (retained && !endpointError) {
183
+ try {
184
+ const current = lstatSync(retained.endpoint);
185
+ if (current.dev !== retained.dev || current.ino !== retained.ino || !current.isSocket()) endpointError = Object.assign(new Error("daemon endpoint was replaced; refusing to unlink another listener"), { code: "daemon_endpoint_identity_mismatch", details: { socket: retained.endpoint, phase: "retire_listener" } });
186
+ } catch (error) { if (error.code !== "ENOENT") endpointError = error; }
187
+ }
188
+ if (endpointError) {
189
+ // libuv's close unlinks by pathname, not inode. Exit without closing its
190
+ // listener handle when the name belongs to a different incarnation.
191
+ const timer = setTimeout(() => { for (const socket of daemonConnections.get(server) ?? []) socket.destroy(); process.exit(1); }, 1_000);
192
+ timer.unref();
193
+ throw endpointError;
194
+ }
195
+ const timer = setTimeout(() => { for (const socket of daemonConnections.get(server) ?? []) socket.destroy(); }, 1_000);
196
+ timer.unref();
197
+ server.close(() => { clearTimeout(timer); process.exit(exitCode); });
198
+ }
199
+
200
+ export async function retireFailedDaemon(server, state, error, persist) {
201
+ // An already-finished registry lease cannot own a listening productive daemon.
202
+ if (state.shutdown?.phases?.daemon_resource) {
203
+ // Durable result publication and listener retirement occur after the
204
+ // cleanup helper returns. Their failures still invalidate overall clean.
205
+ if (persist) try { await persist({ shutdown_state: "cleanup_failed", cleanup_error: errorRecord(error) }); }
206
+ catch (storage) { error.details = { ...error.details, persistence_error: errorRecord(storage) }; }
207
+ process.stderr.write(`${JSON.stringify({ shutdown_failure: errorRecord(error) })}\n`);
208
+ try { retireDaemonEndpoint(server, 1); } catch { /* Retirement already scheduled a nonzero exit without unlinking a foreign endpoint. */ }
209
+ }
210
+ }
211
+
212
+ async function controlDispatch(root, request, action) {
213
+ const key = request.operation === "daemon.stop" ? `stop:${request.params?.cancelTree === true}` : `cancel:${request.params?.sessionId ?? ""}`;
214
+ let pending = controls.get(root);
215
+ if (!pending) { pending = new Map(); controls.set(root, pending); }
216
+ if (pending.has(key)) return await pending.get(key);
217
+ // Preserve the adapter's identity check for every distinct cancel target.
218
+ // A stop arriving after cancel waits for its attempts before verification.
219
+ const predecessors = key.startsWith("stop:") ? [...pending.values()] : [];
220
+ const promise = (async () => { await Promise.allSettled(predecessors); return await action(); })();
221
+ pending.set(key, promise);
222
+ let completed = false;
223
+ try { const result = await promise; completed = true; return result; }
224
+ // Successful whole-tree stop remains idempotent for this daemon lifetime.
225
+ // Durable publication for a concurrent caller may arrive after cleanup ends.
226
+ finally { if (!completed || !key.startsWith('stop:')) { pending.delete(key); if (!pending.size) controls.delete(root); } }
227
+ }
228
+ function location(root, id) {
229
+ if (typeof id !== "string" || !id) throw Object.assign(new Error("operation id is required"), { code: "operation_id_required" });
230
+ return path.join(root, "operations", createHash("sha256").update(id).digest("hex"));
231
+ }
232
+ async function read(file) { try { return JSON.parse(await readFile(file, "utf8")); } catch (error) { if (error.code === "ENOENT") return null; throw error; } }
233
+
234
+ export async function inspectDaemonOperation(root, id) {
235
+ if (typeof root !== "string" || !path.isAbsolute(root)) throw Object.assign(new Error("operation observation requires an absolute state directory"), { code: "invalid_path" });
236
+ const directory = location(root, id);
237
+ const requested = await read(path.join(directory, "requested.json"));
238
+ if (!requested) throw Object.assign(new Error("daemon operation is not recorded"), { code: "operation_not_found", details: { operation_id: id } });
239
+ const settlement = await read(path.join(directory, "settlement.json"));
240
+ const hookFailures = [];
241
+ const hookCorrections = [];
242
+ const hookDiagnostics = [];
243
+ for (const name of await readdir(path.join(directory, "hooks")).catch(error => { if (error.code === "ENOENT") return []; throw error; })) {
244
+ if (!/^[A-Za-z0-9-]{1,128}\.json$/.test(name)) continue;
245
+ const binding = await read(path.join(directory, "hooks", name));
246
+ if (binding?.schema_id !== "dd-flow/hook-request@1" || binding.request_id !== name.slice(0, -5) || binding.operation_id !== id || binding.daemon_id !== requested.daemon_id) continue;
247
+ let failure;
248
+ try { failure = await read(path.join(root, "hook-failures", name)); }
249
+ catch (error) { hookDiagnostics.push({ code: "native_hook_receipt_invalid", message: error.message, request_id: binding.request_id, effect: "unknown", receipt_bound: false }); continue; }
250
+ if (failure?.request_id !== binding.request_id || typeof failure.code !== "string" || typeof failure.message !== "string") continue;
251
+ if (binding.command_sha256 && JSON.stringify(failure.native_hook_binding) !== JSON.stringify(binding)) continue;
252
+ const correction = isProvenShellCorrection(failure);
253
+ (correction ? hookCorrections : hookFailures).push({ ...errorRecord(failure), observed_at: failure.observed_at ?? null, details: { ...failure.details, native_hook_binding: binding, effect: correction ? "no_effect" : "unknown" } });
254
+ }
255
+ hookFailures.sort((a, b) => String(a.observed_at ?? "").localeCompare(String(b.observed_at ?? "")));
256
+ // Admission failure is causal evidence, not proof that the native tree stopped.
257
+ return { ...requested, ...(await read(path.join(directory, "result.json")) ?? await read(path.join(directory, "interrupted.json")) ?? await read(path.join(directory, "observation-lost.json")) ?? { state: "running" }), ...(settlement ? { settlement } : {}), ...(hookFailures[0] ? { primary_error: hookFailures[0] } : {}), ...(hookCorrections.length ? { hook_corrections: hookCorrections } : {}), ...(hookDiagnostics.length ? { hook_diagnostics: hookDiagnostics.slice(0, 16) } : {}) };
258
+ }
259
+
260
+ /** Retry only the bookkeeping that follows a durable productive receipt.
261
+ * This is intentionally separate from dispatch: it never invokes a native
262
+ * prompt/create/fork operation, so recovery cannot duplicate agent work. */
263
+ export async function settleDaemonOperation(root, id) {
264
+ const key = `${root}\0${id}`;
265
+ if (settlements.has(key)) return await settlements.get(key);
266
+ const pending = settleOriginalOperation(root, id);
267
+ settlements.set(key, pending);
268
+ try { return await pending; } finally { if (settlements.get(key) === pending) settlements.delete(key); }
269
+ }
270
+ async function settleOriginalOperation(root, id) {
271
+ const current = await inspectDaemonOperation(root, id);
272
+ if (current.state !== "completed") return current;
273
+ if (['settled', 'not_required'].includes(current.settlement?.state)) return current;
274
+ const daemon = await read(path.join(root, 'daemon.json'));
275
+ const daemonId = daemon?.daemon_id ?? daemon?.config?.daemonId ?? null;
276
+ const fence = await read(path.join(root, 'operation-fence.json'));
277
+ const generation = dispatchGenerations.get(root) ?? (fence?.daemon_id === daemonId ? fence.generation : 0);
278
+ if (current.daemon_id !== (daemon?.daemon_id ?? daemon?.config?.daemonId ?? null)
279
+ || current.owner_id !== undefined && current.owner_id !== (daemon?.config?.runtime_owner?.owner_id ?? null)
280
+ || current.generation !== undefined && current.generation !== generation
281
+ || ['stopping','clean','unclean','cleanup_failed','failed'].includes(daemon?.shutdown_state)) throw Object.assign(new Error('settlement authority changed'), { code: 'settlement_reconciliation_required' });
282
+ assertDaemonDispatch(root);
283
+ let settlement;
284
+ try {
285
+ settlement = await completeBudgetOperation(root, {
286
+ id: current.operation_id,
287
+ operation: current.operation,
288
+ params: { sessionId: current.session_id ?? undefined }
289
+ }, current.result);
290
+ } catch (error) {
291
+ settlement = { state: "pending", reason: "settlement_error", observed_at: new Date().toISOString(), error: errorRecord(error) };
292
+ }
293
+ try { await writeSettlement(root, id, settlement); }
294
+ catch (error) {
295
+ settlement = { state: "blocked", reason: "settlement_storage_error", observed_at: new Date().toISOString(), error: errorRecord(error) };
296
+ }
297
+ return { ...current, settlement };
298
+ }
299
+
300
+ /** A sealed whole-tree stop is the only authority that may turn an unknown
301
+ * productive request into a terminal interruption. This is deliberately a
302
+ * journal operation: a closed daemon cannot be asked to manufacture a reply. */
303
+ export async function interruptDaemonOperation(root, id, barrier) {
304
+ if (!barrier || typeof barrier !== "object" || typeof barrier.control_id !== "string" || !barrier.control_id) throw Object.assign(new Error("interruption requires a sealed control identity"), { code: "stop_barrier_invalid" });
305
+ const current = await inspectDaemonOperation(root, id);
306
+ if (["completed", "failed", "interrupted"].includes(current.state)) return current;
307
+ if (!(["running", "awaiting_provider"].includes(current.state)) || !productive.has(current.operation)) throw Object.assign(new Error("only an observed productive operation may be interrupted"), { code: "operation_not_interruptible" });
308
+ // A lazy session/create is allowed to have no ACP/native session id yet.
309
+ // The owned daemon identity plus the sealed stop operation is the authority
310
+ // in that case; never manufacture a session id merely to satisfy the check.
311
+ const barrierSession = barrier.session_id ?? null;
312
+ const currentSession = current.session_id ?? null;
313
+ if (barrier.daemon_id !== current.daemon_id || barrierSession !== currentSession) throw Object.assign(new Error("interruption barrier belongs to another daemon operation"), { code: "stop_barrier_mismatch" });
314
+ const value = { state: "interrupted", outcome: "interrupted", observed_at: new Date().toISOString(), interrupted_by: { control_id: barrier.control_id, stop_operation_id: barrier.stop_operation_id, evidence: barrier.evidence ?? null }, error: { code: "operation_interrupted", message: "Operation was interrupted after the owned native tree was stopped", cause: current.error ?? null } };
315
+ const saved = await writeTerminal(root, id, value);
316
+ if (saved.state !== "interrupted" || saved.interrupted_by?.control_id !== barrier.control_id) throw Object.assign(new Error("operation already has a conflicting terminal outcome"), { code: "operation_terminal_conflict" });
317
+ return await inspectDaemonOperation(root, id);
318
+ }
319
+
320
+ /** At-most-once dispatch and a durable terminal reply, including when the socket
321
+ * observer disconnects. Recovery reads this receipt; it never resends a prompt. */
322
+ export async function durableDaemonDispatch(root, request, action, observe) {
323
+ if (request.operation === "operation.inspect") return request.params?.settle === true ? await settleDaemonOperation(root, request.params?.operationId) : await inspectDaemonOperation(root, request.params?.operationId);
324
+ if (request.operation === "daemon.status") {
325
+ const result = await action();
326
+ if (!result?.config?.journal) return result;
327
+ try { return { ...result, model_attribution: modelAttribution(await readModelObservations(result.config.journal)) }; }
328
+ catch (error) { return { ...result, model_observation_error: errorRecord(error) }; }
329
+ }
330
+ if (request.operation === "session.inspect") {
331
+ const scope = await budgetObservationScope(root, request.params?.sessionId);
332
+ const result = await action();
333
+ let settlement;
334
+ if (!scope?.operationIds.length) settlement = { state: "not_required" };
335
+ else if (result?.settled !== true) settlement = { state: "pending", reason: "tree_unsettled" };
336
+ else try {
337
+ await releaseBudgetObservation(scope, result);
338
+ settlement = { state: "settled", operation_ids: scope.operationIds, source: "inspection" };
339
+ } catch (error) {
340
+ settlement = { state: "pending", reason: "settlement_error", observed_at: new Date().toISOString(), error: errorRecord(error) };
341
+ }
342
+ return settlement.state === "not_required" || !result || typeof result !== "object" || Array.isArray(result) ? result : { ...result, settlement };
343
+ }
344
+ const control = ["daemon.stop", "session.cancel"].includes(request.operation);
345
+ if (!productive.has(request.operation) && !control) return await action();
346
+ const generation = dispatchGenerations.get(root) ?? 0;
347
+ // Once retirement is committed there is no productive dispatch to cancel.
348
+ // Retrying/joining cleanup must not stale its own durable generation proof.
349
+ if (control && !(request.operation === "daemon.stop" && shutdowns.get(root)?.committed)) { dispatchGenerations.set(root, generation + 1); const state = await read(path.join(root,'daemon.json')); await writeJsonAtomic(path.join(root,'operation-fence.json'), { generation: generation + 1, daemon_id: state?.daemon_id ?? state?.config?.daemonId ?? null }); }
350
+ const assertCurrent = () => { assertDaemonDispatch(root); if (generation !== (dispatchGenerations.get(root) ?? 0)) throw Object.assign(new Error("control cancelled a queued productive dispatch"), { code: "operation_cancelled" }); };
351
+ const stop = request.operation === "daemon.stop" ? (shutdowns.get(root) ?? { pending: 0, committed: false }) : null;
352
+ if (stop) { stop.pending++; shutdowns.set(root, stop); }
353
+ let result;
354
+ try { result = await journalDispatch(root, request, async () => {
355
+ // Persist before admission so a racing fence can observe the writer.
356
+ if (!control) await assertDaemonOwnership(root, { "operation-id": request.id, operation: request.operation, "native-session-id": request.params?.sessionId, "prompt-sha256": typeof request.params?.prompt === "string" ? createHash("sha256").update(request.params.prompt).digest("hex") : undefined }, assertCurrent, phase => publishOperationProgress(root, request.id, phase), receipt => publishOperationWaiting(root,request.id,receipt));
357
+ if (!control) assertCurrent();
358
+ await publishOperationProgress(root, request.id, 'native_dispatched');
359
+ return await withOperationProgress(root, request.id, () => control ? controlDispatch(root, request, action) : action());
360
+ }); } catch (error) {
361
+ if (control) controls.get(root)?.delete(request.operation === 'daemon.stop' ? `stop:${request.params?.cancelTree === true}` : `cancel:${request.params?.sessionId ?? ''}`);
362
+ throw error;
363
+ } finally { if (stop) { stop.pending--; if (!stop.pending && !stop.committed) shutdowns.delete(root); } }
364
+ if (control) return result;
365
+ let settlement;
366
+ await publishRetainedProgress(root, request.id, 'settlement_started', result);
367
+ try {
368
+ settlement = await completeBudgetOperation(root, request, result, observe);
369
+ } catch (error) {
370
+ settlement = { state: "pending", reason: "settlement_error", observed_at: new Date().toISOString(), error: errorRecord(error) };
371
+ }
372
+ try { await writeSettlement(root, request.id, settlement); }
373
+ catch (error) {
374
+ settlement = { state: "blocked", reason: "settlement_storage_error", observed_at: new Date().toISOString(), error: errorRecord(error) };
375
+ }
376
+ await publishRetainedProgress(root, request.id, settlement?.state === 'settled' || settlement?.state === 'not_required' ? 'settlement_completed' : 'settlement_pending', result);
377
+ return settlement?.state === "not_required" || !result || typeof result !== "object" || Array.isArray(result)
378
+ ? result
379
+ : { ...result, settlement };
380
+ }
381
+
382
+ async function writeSettlement(root, id, value) {
383
+ const directory = location(root, id);
384
+ await writeJsonAtomic(path.join(directory, "settlement.json"), value);
385
+ }
386
+
387
+ /** Startup has no registered daemon yet. Its existing native implementation
388
+ * owns registration/admission; only the CLI entrypoint uses this journal path. */
389
+ export async function durableDaemonStart(options, action) {
390
+ const root = options.stateDir;
391
+ if (typeof root !== "string" || !path.isAbsolute(root)) throw Object.assign(new Error("daemon startup requires an absolute state directory"), { code: "invalid_path" });
392
+ // Keep only configuration locations, never inherited credentials. The owned
393
+ // scope can reuse this exact adapter launch after retiring the old daemon.
394
+ const launch = { schema_id: "dd-flow/native-launch@1", executable: options.entryPath ?? null, args: process.argv.slice(2), cwd: process.cwd(), runtime_owner: process.env.DD_FLOW_RUNTIME_OWNER ?? null,
395
+ env: validateNativeLaunchEnvironment(Object.fromEntries([...nativeLaunchEnvironmentKeys, ...(process.env.PLAYWRIGHT_BROWSERS_PATH === undefined ? [] : ["PLAYWRIGHT_BROWSERS_PATH"])].map(key => [key, process.env[key] ?? null]))) };
396
+ const request = prepareDaemonRequest({ id: process.env.DD_EVAL_OPERATION_ID ?? randomUUID(), operation: "daemon.start", params: { ...options, runtimeOwner: process.env.DD_FLOW_RUNTIME_OWNER ?? null, resourceHome: process.env.DD_FLOW_RESOURCE_HOME ?? null, launch } });
397
+ return await journalDispatch(root, request, () => action(options));
398
+ }
399
+
400
+ async function journalDispatch(root, request, action) {
401
+ const directory = location(root, request.id), fingerprint = hashJson({ operation: request.operation, params: request.params ?? {} });
402
+ await mkdir(directory, { recursive: true, mode: 0o700 });
403
+ // Publish a complete request atomically and exclusively. Writing directly with
404
+ // wx exposes a partially written JSON document to a concurrent observer.
405
+ const temporary = path.join(directory, `requested-${randomUUID()}.json`);
406
+ const daemon = await read(path.join(root, "daemon.json"));
407
+ const startup = request.operation === "daemon.start";
408
+ const daemonId = daemon?.daemon_id ?? daemon?.config?.daemonId ?? null;
409
+ await writeJsonAtomic(temporary, { schema_id: "dd-flow/daemon-operation@1", operation_id: request.id, operation: request.operation, session_id: request.params?.sessionId ?? null, daemon_id: startup ? null : daemonId, owner_id: daemon?.config?.runtime_owner?.owner_id ?? null, generation: dispatchGenerations.get(root) ?? 0, ...(startup ? { predecessor_daemon_id: daemonId, launch: request.params?.launch } : {}), params_sha256: fingerprint, ...(request.invocation_sha256 ? { invocation_sha256: request.invocation_sha256 } : {}), requested_at: new Date().toISOString() });
410
+ try {
411
+ await link(temporary, path.join(directory, "requested.json"));
412
+ } catch (error) {
413
+ if (error.code !== "EEXIST") throw error;
414
+ const saved = await inspectDaemonOperation(root, request.id);
415
+ if (saved.params_sha256 !== fingerprint || (saved.invocation_sha256 ?? null) !== (request.invocation_sha256 ?? null)) throw Object.assign(new Error("operation id was reused with different parameters or invocation"), { code: "operation_conflict", details: { operation_id: request.id } });
416
+ if (saved.state === "completed") return saved.result;
417
+ if (["failed", "interrupted"].includes(saved.state)) throw reportedError(saved.error, "provider operation failed");
418
+ throw Object.assign(new Error("provider operation has no confirmed terminal result; inspect the existing operation instead of resending it"), { code: "operation_observation_lost", details: { operation_id: request.id, receipt_directory: directory } });
419
+ } finally { await unlink(temporary); }
420
+ let result;
421
+ await publishOperationProgress(root, request.id, 'accepted');
422
+ try {
423
+ result = await action();
424
+ }
425
+ catch (error) {
426
+ const unknown = isObservationLoss(error);
427
+ if (unknown) await writeJsonAtomic(path.join(directory, "observation-lost.json"), { state: "awaiting_provider", observed_at: new Date().toISOString(), error: errorRecord(error) });
428
+ else {
429
+ const terminal = await writeTerminal(root, request.id, { state: "failed", observed_at: new Date().toISOString(), error: errorRecord(error) });
430
+ if (terminal.state !== "failed") throw reportedError(terminal.error, "provider operation did not retain this failure");
431
+ }
432
+ throw error;
433
+ }
434
+ try {
435
+ const terminal = await writeTerminal(root, request.id, { state: "completed", ...(startup ? { started_daemon_id: result?.daemon_id ?? null } : {}), finished_at: new Date().toISOString(), result });
436
+ if (terminal.state !== "completed") throw reportedError(terminal.error, "provider operation was terminalized before its late reply arrived");
437
+ } catch (cause) {
438
+ if (cause?.code === "operation_interrupted" || cause?.code === "operation_terminal_conflict") throw cause;
439
+ throw Object.assign(new Error("provider returned but the durable reply could not be saved; do not resend the operation"), { code: "operation_observation_lost", cause, details: { operation_id: request.id, receipt_directory: directory } });
440
+ }
441
+ await publishRetainedProgress(root, request.id, 'native_outcome_retained', result, { session_id: result?.session_id ?? result?.sessionId });
442
+ return result;
443
+ }
444
+
445
+ /** `result.json` is the one exclusive terminal slot. Old interrupted.json
446
+ * files remain readable for compatibility, but new writes never race them. */
447
+ async function writeTerminal(root, id, value) {
448
+ const file = path.join(location(root, id), "result.json");
449
+ const temporary = `${file}.${randomUUID()}.tmp`;
450
+ const handle = await open(temporary, "wx", 0o600);
451
+ try { await handle.writeFile(`${JSON.stringify(value, null, 2)}\n`); await handle.sync(); }
452
+ finally { await handle.close(); }
453
+ try {
454
+ await link(temporary, file);
455
+ return value;
456
+ } catch (error) {
457
+ if (error.code !== "EEXIST") throw error;
458
+ const saved = await read(file);
459
+ if (!saved || !["completed", "failed", "interrupted"].includes(saved.state)) throw Object.assign(new Error("operation terminal record is invalid"), { code: "operation_terminal_conflict" });
460
+ return saved;
461
+ } finally { await unlink(temporary); }
462
+ }
@@ -0,0 +1,6 @@
1
+ export declare function qualifyAgyHooks(projectRoot: string, options?: { stateDir?: string | null; install?: boolean }): Promise<{
2
+ hooksSha256: string;
3
+ workspaceHooksPath: string;
4
+ workspaceHooksSha256: string;
5
+ workspaceHooksInstalled: string;
6
+ }>;