@deksden-com/dd-flow-cli 0.9.0-beta.14 → 0.9.0-beta.141

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 (493) hide show
  1. package/CHANGELOG.md +740 -0
  2. package/README.md +143 -1
  3. package/dist/build-info.json +8 -8
  4. package/dist/cli/argument-values.js +38 -0
  5. package/dist/cli/command-inputs.js +376 -0
  6. package/dist/cli/command-metadata.js +197 -0
  7. package/dist/cli/command-option-descriptions.js +191 -0
  8. package/dist/cli/completion-cli.js +70 -0
  9. package/dist/cli/completion.js +57 -0
  10. package/dist/cli/error-output.js +52 -0
  11. package/dist/cli/executor-onboarding.js +76 -0
  12. package/dist/cli/flows.js +29 -0
  13. package/dist/cli/harnesses.js +84 -0
  14. package/dist/cli/help.js +328 -18
  15. package/dist/cli/hook-ingress.js +78 -0
  16. package/dist/cli/input-preparation.js +165 -0
  17. package/dist/cli/memory-flow-admission.js +44 -0
  18. package/dist/cli/memory-init-invocation.js +78 -0
  19. package/dist/cli/memory-init.js +240 -0
  20. package/dist/cli/memory-storage-admission.js +53 -0
  21. package/dist/cli/models.js +39 -0
  22. package/dist/cli/native-hook-ingress.js +80 -0
  23. package/dist/cli/operator-profiles.js +61 -0
  24. package/dist/cli/output-options.js +35 -0
  25. package/dist/cli/response-file.js +71 -0
  26. package/dist/cli/run-cli.js +1689 -545
  27. package/dist/cli/runtime-maintenance-diagnostics.js +46 -0
  28. package/dist/cli/runtime-maintenance-ingress.js +52 -0
  29. package/dist/cli/runtime-process.js +153 -0
  30. package/dist/cli/setup.js +149 -0
  31. package/dist/cli.js +71 -2
  32. package/dist/domain/stage-catalog.js +1 -1
  33. package/dist/domain/stage-handler-identities.js +20 -0
  34. package/dist/harness-runtime/DD-ZCODE.md +112 -0
  35. package/dist/harness-runtime/OPENCODE-LICENSE.txt +24 -0
  36. package/dist/harness-runtime/bin/dd-agy.mjs +56 -0
  37. package/dist/harness-runtime/bin/dd-codex.mjs +27 -0
  38. package/dist/harness-runtime/bin/dd-droid.mjs +34 -0
  39. package/dist/harness-runtime/bin/dd-grok.mjs +40 -0
  40. package/dist/harness-runtime/bin/dd-opencode.mjs +22 -0
  41. package/dist/harness-runtime/bin/dd-zcode.mjs +87 -0
  42. package/dist/harness-runtime/lib/adapter-timeouts.d.mts +5 -0
  43. package/dist/harness-runtime/lib/adapter-timeouts.mjs +34 -0
  44. package/dist/harness-runtime/lib/agy-hooks.d.mts +1 -0
  45. package/dist/harness-runtime/lib/agy-hooks.mjs +9 -0
  46. package/dist/harness-runtime/lib/daemon-observation.d.mts +2 -0
  47. package/dist/harness-runtime/lib/daemon-observation.mjs +163 -0
  48. package/dist/harness-runtime/lib/daemon-operations.d.mts +1 -0
  49. package/dist/harness-runtime/lib/daemon-operations.mjs +371 -0
  50. package/dist/harness-runtime/lib/dd-agy-daemon.d.mts +6 -0
  51. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +728 -0
  52. package/dist/harness-runtime/lib/dd-agy.mjs +70 -0
  53. package/dist/harness-runtime/lib/dd-codex-daemon.d.mts +1 -0
  54. package/dist/harness-runtime/lib/dd-codex-daemon.mjs +196 -0
  55. package/dist/harness-runtime/lib/dd-codex.d.mts +1 -0
  56. package/dist/harness-runtime/lib/dd-codex.mjs +817 -0
  57. package/dist/harness-runtime/lib/dd-droid-daemon.mjs +140 -0
  58. package/dist/harness-runtime/lib/dd-droid.mjs +584 -0
  59. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +498 -0
  60. package/dist/harness-runtime/lib/dd-grok.mjs +177 -0
  61. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +557 -0
  62. package/dist/harness-runtime/lib/dd-opencode.mjs +363 -0
  63. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +751 -0
  64. package/dist/harness-runtime/lib/dd-zcode.mjs +1145 -0
  65. package/dist/harness-runtime/lib/delegation-instructions.d.mts +14 -0
  66. package/dist/harness-runtime/lib/delegation-instructions.mjs +157 -0
  67. package/dist/harness-runtime/lib/dispatch-fence.mjs +14 -0
  68. package/dist/harness-runtime/lib/driver-recovery.mjs +139 -0
  69. package/dist/harness-runtime/lib/droid-observation.mjs +66 -0
  70. package/dist/harness-runtime/lib/lease-renewal.d.mts +8 -0
  71. package/dist/harness-runtime/lib/lease-renewal.mjs +37 -0
  72. package/dist/harness-runtime/lib/lifecycle-command.d.mts +20 -0
  73. package/dist/harness-runtime/lib/lifecycle-command.mjs +273 -0
  74. package/dist/harness-runtime/lib/lifecycle-contract.d.mts +10 -0
  75. package/dist/harness-runtime/lib/lifecycle-contract.mjs +19 -0
  76. package/dist/harness-runtime/lib/managed-daemon.d.mts +16 -0
  77. package/dist/harness-runtime/lib/managed-daemon.mjs +683 -0
  78. package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
  79. package/dist/harness-runtime/lib/model-observations.mjs +101 -0
  80. package/dist/harness-runtime/lib/native-children.d.mts +16 -0
  81. package/dist/harness-runtime/lib/native-children.mjs +113 -0
  82. package/dist/harness-runtime/lib/native-hook-command.d.mts +7 -0
  83. package/dist/harness-runtime/lib/native-hook-command.mjs +251 -0
  84. package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
  85. package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
  86. package/dist/harness-runtime/lib/native-streams.mjs +45 -0
  87. package/dist/harness-runtime/lib/observation-clock.d.mts +18 -0
  88. package/dist/harness-runtime/lib/observation-clock.mjs +92 -0
  89. package/dist/harness-runtime/lib/opencode-plugin.mjs +85 -0
  90. package/dist/harness-runtime/lib/operation-context.mjs +5 -0
  91. package/dist/harness-runtime/lib/operation-errors.d.mts +16 -0
  92. package/dist/harness-runtime/lib/operation-errors.mjs +127 -0
  93. package/dist/harness-runtime/lib/operation-progress.d.mts +7 -0
  94. package/dist/harness-runtime/lib/operation-progress.mjs +114 -0
  95. package/dist/harness-runtime/lib/process-json.d.mts +5 -0
  96. package/dist/harness-runtime/lib/process-json.mjs +201 -0
  97. package/dist/harness-runtime/lib/process-snapshot.mjs +10 -0
  98. package/dist/harness-runtime/lib/provider-overload-policy.d.mts +13 -0
  99. package/dist/harness-runtime/lib/provider-overload-policy.mjs +138 -0
  100. package/dist/harness-runtime/lib/runner-events.mjs +200 -0
  101. package/dist/harness-runtime/lib/runner-lock.mjs +42 -0
  102. package/dist/harness-runtime/lib/session-settlement.mjs +30 -0
  103. package/dist/harness-runtime/lib/setup-progress.d.mts +9 -0
  104. package/dist/harness-runtime/lib/setup-progress.mjs +51 -0
  105. package/dist/harness-runtime/lib/tool-observations.d.mts +21 -0
  106. package/dist/harness-runtime/lib/tool-observations.mjs +228 -0
  107. package/dist/harness-runtime/lib/zcode-usage.mjs +55 -0
  108. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-1y4a697q.js +81 -0
  109. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-2ny4vxct.js +92 -0
  110. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-6mptkzbc.js +0 -0
  111. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-7x67cf1q.js +52 -0
  112. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9rqn6x4v.js +16 -0
  113. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9vdz0zwn.js +1661 -0
  114. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ecs5ftka.js +1466 -0
  115. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-frbwqjmf.js +145 -0
  116. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gne7h7mq.js +50 -0
  117. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gx9wnkzr.js +105 -0
  118. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-m2eywc8w.js +0 -0
  119. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-nwcpakzx.js +12 -0
  120. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-q4g3afnw.js +623 -0
  121. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-qav6mfdz.js +0 -0
  122. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-sxt88q69.js +12 -0
  123. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-t1xa31vm.js +39 -0
  124. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ve4aws36.js +103 -0
  125. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vmytr4q8.js +4 -0
  126. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vt9jbch8.js +36 -0
  127. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vyas3vgt.js +0 -0
  128. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-wjyeq25y.js +30 -0
  129. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-xgnj2w4v.js +20 -0
  130. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-y2etg5bs.js +9 -0
  131. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ydhz1zrh.js +238 -0
  132. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-z6qdwcsf.js +62 -0
  133. package/dist/harness-runtime/vendor/opencode-client/contract.d.ts +1 -0
  134. package/dist/harness-runtime/vendor/opencode-client/contract.js +12 -0
  135. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.d.ts +2806 -0
  136. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.js +0 -0
  137. package/dist/harness-runtime/vendor/opencode-client/effect/api.d.ts +4 -0
  138. package/dist/harness-runtime/vendor/opencode-client/effect/api.js +0 -0
  139. package/dist/harness-runtime/vendor/opencode-client/effect/client.d.ts +2530 -0
  140. package/dist/harness-runtime/vendor/opencode-client/effect/client.js +15 -0
  141. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.d.ts +7 -0
  142. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.js +6 -0
  143. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.d.ts +2529 -0
  144. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.js +8 -0
  145. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.d.ts +2 -0
  146. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.js +12 -0
  147. package/dist/harness-runtime/vendor/opencode-client/effect/index.d.ts +35 -0
  148. package/dist/harness-runtime/vendor/opencode-client/effect/index.js +75 -0
  149. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.d.ts +20 -0
  150. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.js +11 -0
  151. package/dist/harness-runtime/vendor/opencode-client/effect/service.d.ts +90 -0
  152. package/dist/harness-runtime/vendor/opencode-client/effect/service.js +187 -0
  153. package/dist/harness-runtime/vendor/opencode-client/package.json +84 -0
  154. package/dist/harness-runtime/vendor/opencode-client/promise/api.d.ts +21 -0
  155. package/dist/harness-runtime/vendor/opencode-client/promise/api.js +0 -0
  156. package/dist/harness-runtime/vendor/opencode-client/promise/client.d.ts +252 -0
  157. package/dist/harness-runtime/vendor/opencode-client/promise/client.js +14 -0
  158. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.d.ts +8 -0
  159. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.js +6 -0
  160. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.d.ts +259 -0
  161. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.js +7 -0
  162. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.d.ts +3 -0
  163. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.js +79 -0
  164. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.d.ts +8932 -0
  165. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.js +70 -0
  166. package/dist/harness-runtime/vendor/opencode-client/promise/index.d.ts +6 -0
  167. package/dist/harness-runtime/vendor/opencode-client/promise/index.js +83 -0
  168. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.d.ts +32 -0
  169. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.js +7 -0
  170. package/dist/harness-runtime/vendor/opencode-client/promise/service.d.ts +24 -0
  171. package/dist/harness-runtime/vendor/opencode-client/promise/service.js +187 -0
  172. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.d.ts +12 -0
  173. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.js +14 -0
  174. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.d.ts +20 -0
  175. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.js +14 -0
  176. package/dist/harness-runtime/vendor/opencode-client/service-contender.d.ts +37 -0
  177. package/dist/harness-runtime/vendor/opencode-client/service-contender.js +10 -0
  178. package/dist/harness-runtime/vendor/opencode-client/service-probe.d.ts +70 -0
  179. package/dist/harness-runtime/vendor/opencode-client/service-probe.js +16 -0
  180. package/dist/harness-runtime/vendor/opencode-client/service-timing.d.ts +12 -0
  181. package/dist/harness-runtime/vendor/opencode-client/service-timing.js +10 -0
  182. package/dist/harness-runtime/vendor/opencode-client/service-version.d.ts +2 -0
  183. package/dist/harness-runtime/vendor/opencode-client/service-version.js +6 -0
  184. package/dist/harness-runtime/vendor/opencode-client/service.d.ts +52 -0
  185. package/dist/harness-runtime/vendor/opencode-client/service.js +1 -0
  186. package/dist/harness-runtime/vendor/opencode-client/shared-events.d.ts +11 -0
  187. package/dist/harness-runtime/vendor/opencode-client/shared-events.js +8 -0
  188. package/dist/harness-runtime/vendor/opencode-client/solid/connection.d.ts +37 -0
  189. package/dist/harness-runtime/vendor/opencode-client/solid/connection.js +10 -0
  190. package/dist/harness-runtime/vendor/opencode-client/solid/data.d.ts +211 -0
  191. package/dist/harness-runtime/vendor/opencode-client/solid/data.js +18 -0
  192. package/dist/harness-runtime/vendor/opencode-client/solid/index.d.ts +3 -0
  193. package/dist/harness-runtime/vendor/opencode-client/solid/index.js +32 -0
  194. package/dist/harness-runtime/vendor/opencode-client/solid/pty.d.ts +22 -0
  195. package/dist/harness-runtime/vendor/opencode-client/solid/pty.js +8 -0
  196. package/dist/harness-runtime/vendor/opencode-plugin.mjs +3 -0
  197. package/dist/protocol/local-files.js +18 -9
  198. package/dist/runtime/context.js +8 -4
  199. package/dist/schemas/agent-profile.schema.json +1 -1
  200. package/dist/schemas/code-review-result.schema.json +1 -1
  201. package/dist/schemas/code-verification.schema.json +7 -5
  202. package/dist/schemas/code-work-batch.schema.json +2 -2
  203. package/dist/schemas/discovery-result.schema.json +184 -0
  204. package/dist/schemas/execution-bundle.schema.json +205 -0
  205. package/dist/schemas/execution-settings.schema.json +162 -0
  206. package/dist/schemas/flow-descriptor.schema.json +54 -0
  207. package/dist/schemas/flow-run.schema.json +28 -0
  208. package/dist/schemas/harness-catalog.schema.json +80 -0
  209. package/dist/schemas/mb-init-compose-result.schema.json +457 -0
  210. package/dist/schemas/mb-init-discover-result.schema.json +500 -0
  211. package/dist/schemas/mb-init-finish-result.schema.json +422 -0
  212. package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
  213. package/dist/schemas/mb-init-review-result.schema.json +396 -0
  214. package/dist/schemas/mb-init-verify-result.schema.json +391 -0
  215. package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
  216. package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
  217. package/dist/schemas/memory-composition-work-result.schema.json +38 -0
  218. package/dist/schemas/memory-repair-work-result.schema.json +49 -0
  219. package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
  220. package/dist/schemas/memory-review-work-result.schema.json +43 -0
  221. package/dist/schemas/model-catalog.schema.json +153 -0
  222. package/dist/schemas/plan-review-decision.schema.json +3 -3
  223. package/dist/schemas/plan-review-result.schema.json +2 -2
  224. package/dist/schemas/profile-settings.schema.json +122 -0
  225. package/dist/schemas/release-manifest.schema.json +291 -0
  226. package/dist/schemas/run-control-receipt.schema.json +118 -0
  227. package/dist/schemas/run-control-request.schema.json +36 -0
  228. package/dist/schemas/run-engine-binding.schema.json +1 -1
  229. package/dist/schemas/vnext-protocol-plan.schema.json +2 -2
  230. package/dist/services/branch-context.js +3 -3
  231. package/dist/services/canon.js +11 -8
  232. package/dist/services/check-runner-evidence.js +250 -0
  233. package/dist/services/cleanup.js +133 -40
  234. package/dist/services/cli-operation-classifier.js +25 -62
  235. package/dist/services/cli-upgrade-allowlist.js +27 -0
  236. package/dist/services/code-checks.js +1168 -107
  237. package/dist/services/codex-hook-delivery.js +32 -0
  238. package/dist/services/command-context.js +80 -0
  239. package/dist/services/compatibility-preflight.js +13 -3
  240. package/dist/services/config.js +11 -8
  241. package/dist/services/continuation-outcome.js +20 -0
  242. package/dist/services/controller-child-capacity.js +13 -0
  243. package/dist/services/controller-child-observer.js +115 -0
  244. package/dist/services/controller-execution.js +88 -0
  245. package/dist/services/controller-fanout.js +202 -0
  246. package/dist/services/dashboard.js +143 -58
  247. package/dist/services/descriptor-coordinator-session.js +35 -0
  248. package/dist/services/descriptor-root-work.js +53 -0
  249. package/dist/services/descriptor-run-settlement.js +105 -0
  250. package/dist/services/descriptor-run-start.js +449 -0
  251. package/dist/services/descriptor-stage-coordinator.js +197 -0
  252. package/dist/services/descriptor-stage-settlement.js +222 -0
  253. package/dist/services/descriptor-stage-start.js +139 -0
  254. package/dist/services/discovery/agy-discovery.js +2 -0
  255. package/dist/services/discovery/codex-discovery.js +2 -0
  256. package/dist/services/discovery/droid-discovery.js +2 -0
  257. package/dist/services/discovery/grok-discovery.js +2 -0
  258. package/dist/services/discovery/opencode-discovery.js +2 -0
  259. package/dist/services/discovery/static.js +31 -0
  260. package/dist/services/discovery/zcode-discovery.js +2 -0
  261. package/dist/services/engines.js +294 -153
  262. package/dist/services/eval-snapshots.js +1215 -116
  263. package/dist/services/execution-bundles.js +263 -0
  264. package/dist/services/execution-policy.js +185 -0
  265. package/dist/services/executor-onboarding.js +56 -0
  266. package/dist/services/external-work-launch.js +308 -0
  267. package/dist/services/flow-catalog.js +21 -0
  268. package/dist/services/flow-descriptors.js +82 -0
  269. package/dist/services/frozen-engine.js +250 -0
  270. package/dist/services/generic-execution.js +164 -0
  271. package/dist/services/harness-adapter.js +355 -36
  272. package/dist/services/harness-config.js +2 -0
  273. package/dist/services/harness-discovery.js +29 -0
  274. package/dist/services/harness-doctor.js +75 -0
  275. package/dist/services/harness-probe-effects.js +51 -0
  276. package/dist/services/harness-version-probe.js +100 -0
  277. package/dist/services/hooks.js +771 -325
  278. package/dist/services/hybrid-contracts.js +483 -0
  279. package/dist/services/ids.js +29 -1
  280. package/dist/services/installation-lock.js +95 -0
  281. package/dist/services/installed-flow-source.js +183 -0
  282. package/dist/services/lanes.js +78 -65
  283. package/dist/services/lifecycle-command.js +1 -288
  284. package/dist/services/lifecycle-contract.js +1 -0
  285. package/dist/services/lifecycle-invocations.js +2007 -0
  286. package/dist/services/managed-daemon-binding.js +38 -0
  287. package/dist/services/managed-lease-monitor.js +133 -0
  288. package/dist/services/managed-processes.js +475 -55
  289. package/dist/services/memory-accepted-composition.js +77 -0
  290. package/dist/services/memory-baseline-preservation.js +65 -0
  291. package/dist/services/memory-completed-correction-wave.js +320 -0
  292. package/dist/services/memory-compose-handler.js +258 -0
  293. package/dist/services/memory-composition-acceptance.js +199 -0
  294. package/dist/services/memory-composition-graph.js +134 -0
  295. package/dist/services/memory-composition-registration.js +146 -0
  296. package/dist/services/memory-composition-work-custody.js +151 -0
  297. package/dist/services/memory-composition-work-results.js +96 -0
  298. package/dist/services/memory-corrected-review-acceptance.js +129 -0
  299. package/dist/services/memory-corrected-review-batch.js +30 -0
  300. package/dist/services/memory-corrected-review-findings.js +106 -0
  301. package/dist/services/memory-corrected-review-inputs.js +210 -0
  302. package/dist/services/memory-corrected-review-projection.js +78 -0
  303. package/dist/services/memory-corrected-review-receipt.js +170 -0
  304. package/dist/services/memory-corrected-review-registration.js +191 -0
  305. package/dist/services/memory-correction-check-receipt.js +219 -0
  306. package/dist/services/memory-correction-input-owner.js +6 -0
  307. package/dist/services/memory-discover-handler.js +104 -0
  308. package/dist/services/memory-finish-evidence.js +435 -0
  309. package/dist/services/memory-finish-handler.js +215 -0
  310. package/dist/services/memory-finish-integration.js +280 -0
  311. package/dist/services/memory-finish-readiness.js +122 -0
  312. package/dist/services/memory-git-integration.js +151 -0
  313. package/dist/services/memory-historical-corrected-review.js +206 -0
  314. package/dist/services/memory-historical-original-review.js +130 -0
  315. package/dist/services/memory-historical-repair-registration.js +99 -0
  316. package/dist/services/memory-historical-second-review.js +128 -0
  317. package/dist/services/memory-init-bootstrap-readiness.js +210 -0
  318. package/dist/services/memory-init-contexts.js +89 -0
  319. package/dist/services/memory-init-controller-start.js +84 -0
  320. package/dist/services/memory-init-engine-release.js +223 -0
  321. package/dist/services/memory-init-git-policy.js +136 -0
  322. package/dist/services/memory-init-lint-capability.js +185 -0
  323. package/dist/services/memory-init-native-capacity.js +296 -0
  324. package/dist/services/memory-init-preflight.js +330 -0
  325. package/dist/services/memory-init-project-bootstrap.js +599 -0
  326. package/dist/services/memory-init-request-candidate.js +157 -0
  327. package/dist/services/memory-init-request-input.js +66 -0
  328. package/dist/services/memory-init-resource-storage.js +125 -0
  329. package/dist/services/memory-init-run-allocation.js +81 -0
  330. package/dist/services/memory-init-run-bundle.js +98 -0
  331. package/dist/services/memory-init-start.js +181 -0
  332. package/dist/services/memory-init-startup-custody.js +80 -0
  333. package/dist/services/memory-init-startup-input.js +240 -0
  334. package/dist/services/memory-init-storage.js +81 -0
  335. package/dist/services/memory-init-stores.js +359 -0
  336. package/dist/services/memory-init-worktrunk-capability.js +178 -0
  337. package/dist/services/memory-layer-publication.js +611 -0
  338. package/dist/services/memory-layer.js +156 -0
  339. package/dist/services/memory-lint-config.js +85 -0
  340. package/dist/services/memory-native-review-copy.js +165 -0
  341. package/dist/services/memory-normal-flow-entry.js +75 -0
  342. package/dist/services/memory-ordinary-defaults.js +112 -0
  343. package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
  344. package/dist/services/memory-preflight-handler.js +259 -0
  345. package/dist/services/memory-repair-current-view.js +299 -0
  346. package/dist/services/memory-repair-document-delta.js +451 -0
  347. package/dist/services/memory-repair-history.js +491 -0
  348. package/dist/services/memory-repair-physical-binding.js +312 -0
  349. package/dist/services/memory-repair-publication-files.js +152 -0
  350. package/dist/services/memory-repair-publication-intent.js +27 -0
  351. package/dist/services/memory-repair-publication-plan.js +160 -0
  352. package/dist/services/memory-repair-publication-source.js +225 -0
  353. package/dist/services/memory-repair-publication.js +794 -0
  354. package/dist/services/memory-repair-registration.js +239 -0
  355. package/dist/services/memory-repair-work-baseline.js +413 -0
  356. package/dist/services/memory-repair-work-completion.js +97 -0
  357. package/dist/services/memory-repair-work-custody.js +73 -0
  358. package/dist/services/memory-repair-work-results.js +89 -0
  359. package/dist/services/memory-repair-workspace.js +252 -0
  360. package/dist/services/memory-repair-writer-copy.js +735 -0
  361. package/dist/services/memory-result-binding.js +173 -0
  362. package/dist/services/memory-retained-review-authority.js +129 -0
  363. package/dist/services/memory-retained-review-results.js +70 -0
  364. package/dist/services/memory-retained-second-baseline.js +102 -0
  365. package/dist/services/memory-retained-second-repairs.js +156 -0
  366. package/dist/services/memory-review-acceptance.js +214 -0
  367. package/dist/services/memory-review-correction-plan.js +171 -0
  368. package/dist/services/memory-review-handler.js +585 -0
  369. package/dist/services/memory-review-inputs.js +200 -0
  370. package/dist/services/memory-review-receipt.js +180 -0
  371. package/dist/services/memory-review-registration.js +108 -0
  372. package/dist/services/memory-review-work-custody.js +124 -0
  373. package/dist/services/memory-review-work-input.js +72 -0
  374. package/dist/services/memory-review-work-results.js +73 -0
  375. package/dist/services/memory-second-corrected-review-inputs.js +165 -0
  376. package/dist/services/memory-second-correction-plan.js +76 -0
  377. package/dist/services/memory-second-repair-baseline.js +91 -0
  378. package/dist/services/memory-second-repair-launch.js +614 -0
  379. package/dist/services/memory-second-repair-registration.js +88 -0
  380. package/dist/services/memory-second-repair-source.js +187 -0
  381. package/dist/services/memory-second-review-acceptance.js +115 -0
  382. package/dist/services/memory-source-observations.js +117 -0
  383. package/dist/services/memory-stage-dispatch.js +28 -0
  384. package/dist/services/memory-stage-results.js +199 -0
  385. package/dist/services/memory-verification-acceptance.js +135 -0
  386. package/dist/services/memory-verification-checks.js +252 -0
  387. package/dist/services/memory-verification-receipt.js +159 -0
  388. package/dist/services/memory-verify-handler.js +135 -0
  389. package/dist/services/memory-work-result-preparation.js +63 -0
  390. package/dist/services/merge-queue.js +228 -149
  391. package/dist/services/merge-server.js +161 -35
  392. package/dist/services/migrations.js +37 -16
  393. package/dist/services/model-catalog.js +109 -0
  394. package/dist/services/model-discovery.js +46 -0
  395. package/dist/services/native-daemon-history.js +49 -0
  396. package/dist/services/native-session-control.js +39 -0
  397. package/dist/services/operator-profiles.js +236 -0
  398. package/dist/services/plan-runtime.js +26 -11
  399. package/dist/services/plans.js +28 -25
  400. package/dist/services/projects.js +37 -17
  401. package/dist/services/prompts.js +28 -17
  402. package/dist/services/protocols.js +163 -87
  403. package/dist/services/provider-capacity.js +385 -0
  404. package/dist/services/recovery-observation-budget.js +121 -0
  405. package/dist/services/recovery-snapshot-database.js +560 -0
  406. package/dist/services/release-archive-producer.js +52 -0
  407. package/dist/services/release-archive.js +143 -0
  408. package/dist/services/release-cache.js +142 -0
  409. package/dist/services/release-compatibility.js +18 -0
  410. package/dist/services/release-download.js +67 -0
  411. package/dist/services/release-envelope.js +104 -0
  412. package/dist/services/release-manifest.js +45 -0
  413. package/dist/services/release-payload.js +114 -0
  414. package/dist/services/release-producer.js +63 -0
  415. package/dist/services/release-provenance.js +160 -0
  416. package/dist/services/release-registry.js +66 -0
  417. package/dist/services/release-source.js +194 -0
  418. package/dist/services/repair-intents.js +42 -0
  419. package/dist/services/review-copy.js +165 -0
  420. package/dist/services/review-deferral.js +23 -0
  421. package/dist/services/run-control-receipt.js +56 -0
  422. package/dist/services/run-control-worker.js +411 -0
  423. package/dist/services/run-control.js +1056 -0
  424. package/dist/services/run-controller-adapter.js +399 -0
  425. package/dist/services/run-controller-capture.js +186 -0
  426. package/dist/services/run-controller-process.js +208 -0
  427. package/dist/services/run-controller-recovery.js +289 -0
  428. package/dist/services/run-controller-state.js +97 -0
  429. package/dist/services/run-controller.js +1205 -0
  430. package/dist/services/run-engine-bindings.js +1 -1
  431. package/dist/services/run-fork.js +147 -0
  432. package/dist/services/run-health.js +149 -0
  433. package/dist/services/run-observations.js +152 -0
  434. package/dist/services/run-projection.js +22 -64
  435. package/dist/services/run-recovery-guard.js +77 -0
  436. package/dist/services/run-recovery-runtime.js +112 -0
  437. package/dist/services/run-recovery.js +489 -0
  438. package/dist/services/run-start-custody.js +177 -0
  439. package/dist/services/runs.js +1019 -247
  440. package/dist/services/runtime-budget.js +430 -0
  441. package/dist/services/runtime-command.js +43 -0
  442. package/dist/services/runtime-scope-capture.js +52 -0
  443. package/dist/services/runtime-scope-control.js +468 -0
  444. package/dist/services/runtime-scope-resume.js +599 -0
  445. package/dist/services/runtime-scope-stop.js +210 -0
  446. package/dist/services/runtime-scope-worker.js +287 -0
  447. package/dist/services/runtime-service.js +96 -0
  448. package/dist/services/schema-validation.js +10 -8
  449. package/dist/services/scope-writer-cleanup.js +27 -0
  450. package/dist/services/sessions.js +35 -69
  451. package/dist/services/setup.js +377 -0
  452. package/dist/services/stage-blocker.js +17 -7
  453. package/dist/services/stage-context.js +193 -19
  454. package/dist/services/stage-handlers.js +74 -0
  455. package/dist/services/stage-lifecycle.js +152 -116
  456. package/dist/services/stage-pause.js +89 -75
  457. package/dist/services/stage-report-renderer.js +234 -6
  458. package/dist/services/stage-work-graph.js +52 -0
  459. package/dist/services/tooling.js +41 -30
  460. package/dist/services/usage.js +49 -101
  461. package/dist/services/verification-matrix.js +375 -0
  462. package/dist/services/vnext-code-review.js +223 -88
  463. package/dist/services/vnext-code.js +327 -226
  464. package/dist/services/vnext-contracts.js +10 -1
  465. package/dist/services/vnext-execution-profile.js +80 -5
  466. package/dist/services/vnext-fanout.js +311 -19
  467. package/dist/services/vnext-merge.js +332 -111
  468. package/dist/services/vnext-plan-review.js +279 -127
  469. package/dist/services/vnext-plan.js +228 -104
  470. package/dist/services/vnext-protocolize.js +531 -95
  471. package/dist/services/vnext-specify.js +119 -81
  472. package/dist/services/vnext-workspace-policy.js +7 -2
  473. package/dist/services/work-registry.js +1627 -199
  474. package/dist/services/workspace-bootstrap.js +52 -15
  475. package/dist/services/workspace-files.js +85 -0
  476. package/dist/services/worktrees.js +105 -48
  477. package/dist/shared/entity-references.js +8 -0
  478. package/dist/shared/errors.js +27 -0
  479. package/dist/storage/agent-output.js +26 -0
  480. package/dist/storage/database.js +891 -39
  481. package/dist/storage/foreign-key-transaction.js +39 -0
  482. package/dist/storage/immutable-input.js +45 -0
  483. package/dist/storage/import-guard.js +102 -0
  484. package/dist/storage/native-cleanup.js +52 -0
  485. package/dist/storage/paths.js +17 -4
  486. package/dist/storage/projection-lock.js +73 -0
  487. package/dist/storage/work-references.js +23 -0
  488. package/dist/storage/writer-contract.js +89 -0
  489. package/dist/storage/writer-migration.js +85 -0
  490. package/package.json +43 -13
  491. package/tools/create-canon-release.mjs +33 -0
  492. package/tools/produce-hybrid-release.mjs +41 -0
  493. package/tools/repair-paused-run-status.mjs +84 -0
@@ -0,0 +1,156 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { createHash } from "node:crypto";
4
+ import { Ajv } from "ajv/dist/ajv.js";
5
+ import semver from "semver";
6
+ import { AppError } from "../shared/errors.js";
7
+ import { hybridDigest } from "./hybrid-contracts.js";
8
+ import { readSetupStatus } from "./setup.js";
9
+ import { readBoundedReleaseFile } from "./release-source.js";
10
+ import { normalizeFlowContract } from "../domain/flow-contract.js";
11
+ const rootFiles = ["README.md", "index.md", "compatibility.json", "flow-contract.json", "go.md", "f.md", "prime.md", "protocol.md",
12
+ "protocol-implement.md", "plan.md", "code.md", "merge.md", "merge-start.md", "merge-stop.md", "release.md", "deploy.md", "publish.md",
13
+ "review.md", "review-fix.md", "mb-audit.md", "mb-fix.md", "mb-lint.md", "interactive.md", "finish.md", "fix-def.md"];
14
+ const supportDirectories = ["common", "prime", "mb-sdlc", "aspects", "def", "workers", "mb-audit", "schemas", "vnext", "specify", "stage-reports", "dashboard", "plan", "code", "merge"];
15
+ const required = ["README.md", "index.md", "flow-contract.json", "compatibility.json", "prime.md", "go.md",
16
+ "common/style.md", "common/runtime-contract.md", "common/lifecycle-guards.md", "common/workspace-bootstrap.md", "common/worker-session.md",
17
+ "vnext/start.md", "vnext/specify.md", "vnext/protocolize.md", "vnext/plan.md", "vnext/plan-review.md", "vnext/code.md", "vnext/code-review.md", "vnext/merge.md",
18
+ "schemas/flow-run.schema.json", "schemas/project-flow-pack-manifest.schema.json"];
19
+ const hash = (bytes) => createHash("sha256").update(bytes).digest("hex");
20
+ function refuse(reason) {
21
+ throw new AppError("memory_layer_invalid", "Selected Memory Bank layer cannot be prepared", 1, { reason, phase: "prepare", effect: "no_effect" });
22
+ }
23
+ function directory(file) { if (!fs.lstatSync(file).isDirectory())
24
+ refuse("unsafe_source_directory"); }
25
+ /** Canonical-layer bytes only, not project facts, a productive bootstrap receipt or qualification.
26
+ * The source must be the independently selected, verified installed release cache.
27
+ */
28
+ export class PreparedMemoryLayer {
29
+ sha256;
30
+ packSha256;
31
+ installationSha256;
32
+ #files;
33
+ constructor(files, installationSha256) {
34
+ this.#files = files;
35
+ this.installationSha256 = installationSha256;
36
+ const inventory = [...files].map(([logical, bytes]) => ({ path: logical, sha256: hash(bytes) }));
37
+ this.sha256 = hybridDigest(inventory);
38
+ this.packSha256 = hybridDigest(inventory.filter(item => item.path.startsWith("dd-flow/")));
39
+ Object.freeze(this);
40
+ }
41
+ static fromInstalledRelease(home, expectedInstallationSha256, installedAt) {
42
+ try {
43
+ if (!path.isAbsolute(home) || !/^[a-f0-9]{64}$/.test(expectedInstallationSha256)
44
+ || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/.test(installedAt) || !Number.isFinite(Date.parse(installedAt)))
45
+ refuse("invalid_selection");
46
+ const selection = readSetupStatus(home);
47
+ if (!selection.installation || selection.installation_readiness !== "installed")
48
+ refuse("installed_release_unavailable");
49
+ const installation = selection.installation;
50
+ if (installation.manifest_sha256 !== expectedInstallationSha256)
51
+ refuse("installation_selection_changed");
52
+ directory(installation.canon_root);
53
+ const roots = fs.readdirSync(installation.canon_root);
54
+ if (roots.length !== 1)
55
+ refuse("ambiguous_archive_root");
56
+ const canonRoot = path.join(installation.canon_root, roots[0]);
57
+ directory(canonRoot);
58
+ const dotRoot = path.join(canonRoot, ".memory-bank");
59
+ const memoryRoot = fs.existsSync(dotRoot) ? dotRoot : canonRoot;
60
+ directory(memoryRoot);
61
+ const files = new Map(), folded = new Set();
62
+ let total = 0;
63
+ const put = (logical, bytes) => {
64
+ if (bytes.length < 1 || bytes.length > 1024 * 1024 || !/^[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)*$/.test(logical) || logical.split("/").some(part => [".", ".."].includes(part))
65
+ || folded.has(logical.toLowerCase()) || (total += bytes.length) > 64 * 1024 * 1024)
66
+ refuse("unsafe_or_unbounded_inventory");
67
+ folded.add(logical.toLowerCase());
68
+ files.set(logical, Buffer.from(bytes));
69
+ };
70
+ const collect = (source, logical) => {
71
+ directory(source);
72
+ for (const name of fs.readdirSync(source).sort()) {
73
+ const file = path.join(source, name), target = `${logical}/${name}`, stat = fs.lstatSync(file);
74
+ if (stat.isDirectory())
75
+ collect(file, target);
76
+ else if (stat.isFile())
77
+ put(target, readBoundedReleaseFile(file, 1024 * 1024));
78
+ else
79
+ refuse("unsafe_source_file");
80
+ }
81
+ };
82
+ collect(path.join(memoryRoot, "mbb"), "mbb");
83
+ if (!files.has("mbb/index.md"))
84
+ refuse("missing_mbb_entrypoint");
85
+ const flowRoot = path.join(memoryRoot, "dd-flow");
86
+ directory(flowRoot);
87
+ for (const name of rootFiles)
88
+ if (fs.existsSync(path.join(flowRoot, name)))
89
+ put(`dd-flow/${name}`, readBoundedReleaseFile(path.join(flowRoot, name), 1024 * 1024));
90
+ for (const name of supportDirectories)
91
+ if (fs.existsSync(path.join(flowRoot, name)))
92
+ collect(path.join(flowRoot, name), `dd-flow/${name}`);
93
+ if (required.some(logical => !files.has(`dd-flow/${logical}`)))
94
+ refuse("incomplete_project_pack");
95
+ const contract = normalizeFlowContract(JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(files.get("dd-flow/flow-contract.json"))));
96
+ const compatibility = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(files.get("dd-flow/compatibility.json")));
97
+ const compatibilitySchema = JSON.parse(fs.readFileSync(new URL("../schemas/compatibility.schema.json", import.meta.url), "utf8"));
98
+ if (!new Ajv({ strict: false, validateFormats: false }).compile(compatibilitySchema)(compatibility))
99
+ refuse("invalid_compatibility");
100
+ if (compatibility.memory_bank_version !== installation.manifest.canon.version
101
+ || compatibility.dd_flow_cli.flow_contract !== contract.id
102
+ || compatibility.dd_flow_cli.package_name !== installation.manifest.engine.package
103
+ || compatibility.engine.package_name !== installation.manifest.engine.package
104
+ || !semver.validRange(compatibility.engine.version_range)
105
+ || !semver.satisfies(installation.manifest.engine.version, compatibility.engine.version_range, { includePrerelease: true })
106
+ || !semver.valid(compatibility.dd_flow_cli.min_version)
107
+ || semver.lt(installation.manifest.engine.version, compatibility.dd_flow_cli.min_version))
108
+ refuse("incompatible_selected_release");
109
+ const included = [...files.keys()].filter(logical => logical.startsWith("dd-flow/")).map(logical => logical.slice(8)).sort();
110
+ const manifest = { schema_id: "dd-flow/project-flow-pack-manifest@2", pack_version: installation.manifest.canon.version,
111
+ flow_origin_policy: "project_local_pack", canon_root: canonRoot, canon_memory_bank_root: memoryRoot, canon_flow_root: flowRoot,
112
+ source_commit: installation.manifest.canon.commit, canon_version_at_source_commit: installation.manifest.canon.version,
113
+ flow_contract: contract.id, installed_at: installedAt, included_files: included,
114
+ file_hashes: Object.fromEntries(included.map(logical => [logical, hash(files.get(`dd-flow/${logical}`))])),
115
+ excluded_canonical_only_flows: ["mb-init.md", "mb-upgrade.md", "mb-distill.md"], generated_allow_patterns: [".generated/**"] };
116
+ const schema = JSON.parse(fs.readFileSync(new URL("../schemas/project-flow-pack-manifest.schema.json", import.meta.url), "utf8"));
117
+ if (!new Ajv({ strict: false, validateFormats: false }).compile(schema)(manifest))
118
+ refuse("invalid_pack_manifest");
119
+ const retainedSchema = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(files.get("dd-flow/schemas/project-flow-pack-manifest.schema.json")));
120
+ if (retainedSchema.$id !== "dd-flow/project-flow-pack-manifest@2"
121
+ || !new Ajv({ strict: false, validateFormats: false }).compile(retainedSchema)(manifest))
122
+ refuse("invalid_retained_manifest_schema");
123
+ put("dd-flow/manifest.json", Buffer.from(`${JSON.stringify(manifest, null, 2)}\n`));
124
+ return new PreparedMemoryLayer(new Map([...files].sort(([left], [right]) => left.localeCompare(right, "en"))), expectedInstallationSha256);
125
+ }
126
+ catch (error) {
127
+ if (error instanceof AppError && error.code === "memory_layer_invalid")
128
+ throw error;
129
+ return refuse("source_unavailable_or_changed");
130
+ }
131
+ }
132
+ files() { return new Map([...this.#files].map(([logical, bytes]) => [logical, Buffer.from(bytes)])); }
133
+ /** Restore only with an independently retained hash of an already admitted layer.
134
+ * SHA admission proves the original verified bytes; mutable installation sources are not read.
135
+ */
136
+ static restoreRetained(files, expectedSha256, installationSha256) {
137
+ if (!/^[a-f0-9]{64}$/.test(expectedSha256) || !/^[a-f0-9]{64}$/.test(installationSha256)
138
+ || files.size < 1 || files.size > 20_000)
139
+ refuse("invalid_retained_selection");
140
+ let total = 0;
141
+ const folded = new Set(), retained = new Map();
142
+ for (const [logical, content] of files) {
143
+ if (!/^(?:mbb|dd-flow)\/[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)*$/.test(logical)
144
+ || logical.split("/").some(segment => segment === "." || segment === "..")
145
+ || folded.has(logical.toLowerCase()) || content.length < 1 || content.length > 1024 * 1024
146
+ || (total += content.length) > 64 * 1024 * 1024)
147
+ refuse("unsafe_or_unbounded_inventory");
148
+ folded.add(logical.toLowerCase());
149
+ retained.set(logical, Buffer.from(content));
150
+ }
151
+ const result = new PreparedMemoryLayer(new Map([...retained].sort(([left], [right]) => left.localeCompare(right, "en"))), installationSha256);
152
+ if (result.sha256 !== expectedSha256)
153
+ refuse("retained_layer_changed");
154
+ return result;
155
+ }
156
+ }
@@ -0,0 +1,85 @@
1
+ import { AppError } from "../shared/errors.js";
2
+ /** Review inputs also contain immutable guidance; only accepted current unit
3
+ * artifacts are project output that lint configuration must not suppress. */
4
+ export function memoryVerificationActivePaths(units, assignments = []) {
5
+ return [".memory-bank/index.md", ".memory-bank/structure.md", ".memory-bank/project-policy.md",
6
+ ...units.flatMap(unit => (assignments.find(assignment => assignment.unit.id === unit.id)?.unit ?? unit).artifacts
7
+ .filter(artifact => artifact.root === "workspace").map(artifact => artifact.path))];
8
+ }
9
+ /** Bootstrap-owned policy for immutable guidance, never project knowledge or
10
+ * the two project-owned JSON defaults beside the canonical flow pack. */
11
+ export function defaultMemoryLintConfiguration() {
12
+ return Buffer.from(`${JSON.stringify({
13
+ ignorePaths: [".memory-bank/dd-flow/*.md", ".memory-bank/dd-flow/**/*.md", ".memory-bank/mbb/templates/**"],
14
+ ignoreFindings: [{ ruleId: "def/required-fields", file: ".memory-bank/mbb/named-deferrals-guide.md",
15
+ target: "DEF-UI-PROTECTED-BROWSER-PROOF", reason: "Illustrative DEF in immutable canonical guidance, not a project deferral." }]
16
+ }, null, 2)}\n`);
17
+ }
18
+ function refuse(reason) {
19
+ throw new AppError("memory_lint_config_invalid", "Lint configuration cannot suppress active memory verification", 2, { reason, effect: "no_effect" });
20
+ }
21
+ function record(value) {
22
+ if (!value || typeof value !== "object" || Array.isArray(value))
23
+ refuse("invalid_config_object");
24
+ return value;
25
+ }
26
+ function patterns(value) {
27
+ if (value === undefined)
28
+ return [];
29
+ if (!Array.isArray(value) || value.some(pattern => typeof pattern !== "string" || !pattern.trim() || pattern.includes("\0")))
30
+ refuse("invalid_ignore_paths");
31
+ return value;
32
+ }
33
+ // mb-lint's documented matcher uses literal characters plus * and **, not
34
+ // shell/extglob semantics. Backslashes are normalized to portable separators.
35
+ function matches(pattern, file) {
36
+ const portable = pattern.replaceAll("\\", "/");
37
+ if (["?", "[", "]", "{", "}", "!", "(", ")"].some(character => portable.includes(character)) || portable.split("/").some(segment => !segment || segment === "." || segment === ".."))
38
+ refuse("unsupported_ignore_pattern");
39
+ const chunks = portable.split(/(\*\*|\*)/);
40
+ const source = chunks.map(chunk => chunk === "**" ? ".*" : chunk === "*" ? "[^/]*" : chunk.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&")).join("");
41
+ return new RegExp(`^${source}$`).test(file.replaceAll("\\", "/"));
42
+ }
43
+ /** Pure admission, no writes or inference of semantic completeness. Protected
44
+ * paths come from accepted composition plus required active root documents.
45
+ * Existing config bytes remain user-owned; exclusion repair is not automatic.
46
+ */
47
+ export function validateMemoryLintConfig(bytes, activePaths) {
48
+ if (!(bytes instanceof Uint8Array) || !bytes.length || bytes.length > 1024 * 1024)
49
+ refuse("invalid_config_bytes");
50
+ let parsed;
51
+ try {
52
+ parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
53
+ }
54
+ catch {
55
+ return refuse("invalid_config_json");
56
+ }
57
+ const config = record(parsed), allowed = new Set(["ignorePaths", "ignoreFindings", "ignore", "git"]);
58
+ if (Object.keys(config).some(key => !allowed.has(key)))
59
+ refuse("unsupported_config_field");
60
+ const nested = config.ignore === undefined ? {} : record(config.ignore);
61
+ if (Object.keys(nested).some(key => !['files', 'findings'].includes(key)))
62
+ refuse("unsupported_ignore_field");
63
+ const paths = [...patterns(config.ignorePaths), ...patterns(nested.files)];
64
+ if (paths.some(pattern => activePaths.some(file => matches(pattern, file))))
65
+ refuse("active_document_ignored");
66
+ for (const list of [config.ignoreFindings, nested.findings]) {
67
+ if (list === undefined)
68
+ continue;
69
+ if (!Array.isArray(list))
70
+ refuse("invalid_ignore_findings");
71
+ for (const item of list) {
72
+ const finding = record(item);
73
+ if (Object.keys(finding).some(key => !['ruleId', 'file', 'target', 'reason'].includes(key))
74
+ || Object.values(finding).some(value => typeof value !== "string" || !value.trim() || value.includes("\0")))
75
+ refuse("invalid_ignore_finding");
76
+ if (typeof finding.file !== "string" || activePaths.some(file => matches(finding.file, file)))
77
+ refuse("active_finding_suppressed");
78
+ }
79
+ }
80
+ if (config.git !== undefined) {
81
+ const git = record(config.git);
82
+ if (Object.keys(git).some(key => key !== "respectIgnore") || git.respectIgnore !== undefined && typeof git.respectIgnore !== "boolean")
83
+ refuse("invalid_git_config");
84
+ }
85
+ }
@@ -0,0 +1,165 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { createHash } from "node:crypto";
4
+ import { AppError } from "../shared/errors.js";
5
+ import { appendAudit } from "./audit.js";
6
+ import { hybridDigest } from "./hybrid-contracts.js";
7
+ import { prepareMemoryReviewWorkInput, assertPreparedMemoryReviewWorkInput } from "./memory-review-work-input.js";
8
+ import { assertRunMutationAllowed } from "./run-recovery-guard.js";
9
+ import { reviewSourceFilter, reviewSourceHash, reviewExecutionCopyHash } from "./review-copy.js";
10
+ import { writeReviewGitEvidence } from "./external-work-launch.js";
11
+ function refuse(reason) { throw new AppError("memory_native_review_copy_invalid", "Native Memory review requires an independently owned immutable execution copy", 1, { reason, effect: "no_effect" }); }
12
+ function physicalDestination(runRoot, relative) {
13
+ if (fs.realpathSync(runRoot) !== path.resolve(runRoot) || !fs.lstatSync(runRoot).isDirectory())
14
+ refuse("noncanonical_run_root");
15
+ let current = runRoot;
16
+ for (const part of relative.split("/")) {
17
+ if (!part || part === "." || part === "..")
18
+ refuse("invalid_copy_path");
19
+ current = path.join(current, part);
20
+ const stat = fs.lstatSync(current, { throwIfNoEntry: false });
21
+ if (stat && !stat.isDirectory())
22
+ refuse("linked_or_non_directory_copy_path");
23
+ if (!stat)
24
+ break;
25
+ }
26
+ }
27
+ /** Routing is not fresh source admission: an already claimed reviewer retains
28
+ * its committed private directory even after a later correction changes MB. */
29
+ export function memoryNativeReviewAssignedHookCwd(context, input) {
30
+ const work = context.db.get("SELECT status,payload_json FROM works WHERE project_id=? AND run_id=? AND work_id=?", [input.projectId, input.runId, input.workId]);
31
+ const payload = JSON.parse(work?.payload_json ?? "null");
32
+ if (payload?.kind !== "memory-review" || payload.read_only !== true)
33
+ return null;
34
+ const ready = context.db.get("SELECT 1 FROM audit_events WHERE project_id=? AND event_type='memory.native_review_copy_ready' AND json_extract(payload_json,'$.intent.run_id')=? AND json_extract(payload_json,'$.intent.work_id')=?", [input.projectId, input.runId, input.workId]);
35
+ if (!ready)
36
+ return null;
37
+ if (work?.status === "created") {
38
+ // Hook ingress routes an already allocated copy. Source admission belongs
39
+ // to the actual work-start owner, not a second physical graph in the Hook.
40
+ const generation = assertRunMutationAllowed(context, input.projectId, input.runId);
41
+ const run = context.db.get("SELECT run_root,run_dir FROM runs WHERE project_id=? AND id=?", [input.projectId, input.runId]);
42
+ if (!run)
43
+ refuse("owned_run_required");
44
+ const rows = (event) => context.db.all("SELECT payload_json FROM audit_events WHERE project_id=? AND event_type=? AND COALESCE(json_extract(payload_json,'$.run_id'),json_extract(payload_json,'$.intent.run_id'))=? AND COALESCE(json_extract(payload_json,'$.work_id'),json_extract(payload_json,'$.intent.work_id'))=? AND COALESCE(json_extract(payload_json,'$.generation'),json_extract(payload_json,'$.intent.generation'))=? LIMIT 2", [input.projectId, event, input.runId, input.workId, generation]);
45
+ const intents = rows("memory.native_review_copy_intent"), copies = rows("memory.native_review_copy_ready");
46
+ if (intents.length !== 1 || copies.length !== 1)
47
+ refuse("registered_copy_required");
48
+ const intent = JSON.parse(intents[0].payload_json), copy = JSON.parse(copies[0].payload_json);
49
+ const relative = `works/${input.workId}/native-review-workspaces/generation-${generation}`, runRoot = run.run_root ?? run.run_dir;
50
+ if (intent.schema_id !== "dd-flow/memory-native-review-copy@1" || intent.project_id !== input.projectId || intent.run_id !== input.runId
51
+ || intent.work_id !== input.workId || intent.generation !== generation || intent.root !== relative
52
+ || !/^[a-f0-9]{64}$/.test(intent.input_sha256) || !/^[a-f0-9]{64}$/.test(intent.source_sha256)
53
+ || hybridDigest(copy.intent) !== hybridDigest(intent) || !/^[a-f0-9]{64}$/.test(copy.sha256))
54
+ refuse("registered_copy_changed");
55
+ physicalDestination(runRoot, relative);
56
+ const root = path.join(runRoot, relative);
57
+ if (!fs.lstatSync(root, { throwIfNoEntry: false })?.isDirectory())
58
+ refuse("registered_copy_required");
59
+ return root;
60
+ }
61
+ const rows = context.db.all("SELECT ws.start_receipt_json,r.run_root,r.run_dir,s.cwd FROM work_sessions ws JOIN works w ON w.work_id=ws.work_id JOIN runs r ON r.project_id=w.project_id AND r.id=w.run_id JOIN sessions s ON s.project_id=w.project_id AND s.session_id=ws.session_id WHERE w.project_id=? AND w.run_id=? AND w.work_id=? AND s.provider_session_id=? AND s.worker_id=w.work_id AND EXISTS(SELECT 1 FROM audit_events a WHERE a.project_id=w.project_id AND a.event_type='memory.native_review_binding' AND json_extract(a.payload_json,'$.work_session_id')=ws.id AND json_extract(a.payload_json,'$.run_id')=w.run_id AND json_extract(a.payload_json,'$.work_id')=w.work_id) LIMIT 2", [input.projectId, input.runId, input.workId, input.providerSessionId]);
62
+ if (rows.length !== 1)
63
+ refuse("registered_session_required");
64
+ const row = rows[0];
65
+ if (typeof row.start_receipt_json !== "string" || Buffer.byteLength(row.start_receipt_json) > 16 * 1024 * 1024)
66
+ refuse("registered_copy_required");
67
+ const receipt = JSON.parse(row.start_receipt_json), packet = JSON.parse(receipt.context);
68
+ const relative = `works/${input.workId}/native-review-workspaces/generation-${receipt.generation}`, root = path.join(row.run_root ?? row.run_dir, relative);
69
+ if (receipt.version !== 2 || createHash("sha256").update(receipt.context).digest("hex") !== receipt.context_sha256
70
+ || packet.work_id !== input.workId || packet.run_id !== input.runId || packet.workspace_root !== root
71
+ || packet.review_copy?.root !== relative || row.cwd !== root)
72
+ refuse("registered_copy_changed");
73
+ return root;
74
+ }
75
+ /** Existing source/copy policy, separate native physical custody: no external
76
+ * launch row is invented. An interrupted allocation is never overwritten. */
77
+ export function prepareMemoryNativeReviewCopy(context, workId, allocate = false, preparedOwner) {
78
+ const work = context.db.get("SELECT * FROM works WHERE work_id=?", [workId]);
79
+ if (!work)
80
+ refuse("owned_work_required");
81
+ const run = context.db.get("SELECT * FROM runs WHERE project_id=? AND id=?", [work.project_id, work.run_id]);
82
+ if (!run)
83
+ refuse("owned_run_required");
84
+ const generation = assertRunMutationAllowed(context, work.project_id, work.run_id);
85
+ const owner = preparedOwner ?? prepareMemoryReviewWorkInput(context, work, run, generation);
86
+ assertPreparedMemoryReviewWorkInput(context, owner, work, run, generation);
87
+ const route = owner.bundle.execution.work("review");
88
+ if (route.delegation.mode !== "native")
89
+ refuse("native_route_required");
90
+ const relative = `works/${workId}/native-review-workspaces/generation-${generation}`;
91
+ const runRoot = run.run_root ?? run.run_dir, root = path.join(runRoot, relative);
92
+ physicalDestination(runRoot, relative);
93
+ const inputs = owner.input.run_inputs.filter(ref => ref.root === "workspace").map(ref => ref.path);
94
+ const selectedBase = JSON.parse(run.index_json).workspace?.base;
95
+ const base = selectedBase && selectedBase !== "unknown" ? selectedBase : "HEAD";
96
+ const intent = { schema_id: "dd-flow/memory-native-review-copy@1", project_id: work.project_id, run_id: work.run_id,
97
+ work_id: workId, generation, root: relative, input_sha256: hybridDigest(owner.input), source_sha256: reviewSourceHash(run.workspace_root, inputs, base) };
98
+ // A recovery generation gets a new owned copy; never adopt the previous
99
+ // generation's journal or overwrite its physical evidence.
100
+ const retained = (event, reader = context) => reader.db.all("SELECT payload_json FROM audit_events WHERE project_id=? AND event_type=? AND COALESCE(json_extract(payload_json,'$.run_id'),json_extract(payload_json,'$.intent.run_id'))=? AND COALESCE(json_extract(payload_json,'$.work_id'),json_extract(payload_json,'$.intent.work_id'))=? AND COALESCE(json_extract(payload_json,'$.generation'),json_extract(payload_json,'$.intent.generation'))=? LIMIT 2", [work.project_id, event, work.run_id, workId, generation]);
101
+ const ready = retained("memory.native_review_copy_ready");
102
+ let copy;
103
+ if (ready.length) {
104
+ if (ready.length !== 1)
105
+ refuse("ambiguous_copy");
106
+ const intents = retained("memory.native_review_copy_intent");
107
+ if (intents.length !== 1 || hybridDigest(JSON.parse(intents[0].payload_json)) !== hybridDigest(intent))
108
+ refuse("copy_custody_changed");
109
+ const value = JSON.parse(ready[0].payload_json);
110
+ if (hybridDigest(value.intent) !== hybridDigest(intent) || !/^[a-f0-9]{64}$/.test(value.sha256))
111
+ refuse("copy_or_source_changed");
112
+ copy = { root: relative, sha256: value.sha256, source_sha256: intent.source_sha256 };
113
+ }
114
+ else {
115
+ if (!allocate)
116
+ refuse("ready_copy_required");
117
+ if (retained("memory.native_review_copy_intent").length || fs.lstatSync(root, { throwIfNoEntry: false }))
118
+ refuse("copy_allocation_unsettled");
119
+ owner.revalidate(context);
120
+ context.db.writeTransaction(() => {
121
+ owner.assertCustody(context);
122
+ if (retained("memory.native_review_copy_intent").length)
123
+ refuse("copy_allocation_unsettled");
124
+ appendAudit(context, { projectId: work.project_id, eventType: "memory.native_review_copy_intent", payload: intent });
125
+ });
126
+ try {
127
+ fs.mkdirSync(path.dirname(root), { recursive: true, mode: 0o700 });
128
+ physicalDestination(runRoot, relative);
129
+ fs.mkdirSync(root, { mode: 0o700 }); // Exclusive: never adopt an existing or partial destination.
130
+ physicalDestination(runRoot, relative);
131
+ fs.cpSync(run.workspace_root, root, { recursive: true, verbatimSymlinks: true, force: false, errorOnExist: true, filter: reviewSourceFilter(run.workspace_root, inputs, base) });
132
+ if (reviewSourceHash(run.workspace_root, inputs, base) !== intent.source_sha256
133
+ || reviewExecutionCopyHash(root, run.workspace_root, false, inputs, base) !== intent.source_sha256)
134
+ refuse("copy_or_source_changed");
135
+ writeReviewGitEvidence(run.workspace_root, root, base, inputs);
136
+ owner.revalidate(context);
137
+ if (reviewSourceHash(run.workspace_root, inputs, base) !== intent.source_sha256
138
+ || reviewExecutionCopyHash(root, run.workspace_root, false, inputs, base) !== intent.source_sha256)
139
+ refuse("copy_or_source_changed");
140
+ copy = { root: relative, source_sha256: intent.source_sha256, sha256: reviewExecutionCopyHash(root, run.workspace_root, true, inputs, base) };
141
+ context.db.writeTransaction(() => {
142
+ owner.assertCustody(context);
143
+ if (retained("memory.native_review_copy_ready").length)
144
+ refuse("copy_allocation_unsettled");
145
+ appendAudit(context, { projectId: work.project_id, eventType: "memory.native_review_copy_ready", payload: { intent, sha256: copy.sha256 } });
146
+ });
147
+ }
148
+ catch (error) {
149
+ throw new AppError("memory_native_review_copy_pending", "Native review copy allocation is retained and cannot be replayed or overwritten", 1, { effect: "partial", recoverable: false, work_id: workId, copy_root: root, next_action: "Inspect the exact retained copy intent and private destination; do not relaunch or adopt partial files.",
150
+ cause: error instanceof Error ? error.message : String(error) });
151
+ }
152
+ }
153
+ if (reviewExecutionCopyHash(root, run.workspace_root, true, inputs, base) !== copy.sha256)
154
+ refuse("copy_changed");
155
+ const assertCustody = (writer) => {
156
+ owner.assertCustody(writer);
157
+ assertRunMutationAllowed(writer, work.project_id, work.run_id, generation);
158
+ const rows = retained("memory.native_review_copy_ready", writer);
159
+ const intents = retained("memory.native_review_copy_intent", writer);
160
+ if (intents.length !== 1 || hybridDigest(JSON.parse(intents[0].payload_json)) !== hybridDigest(intent)
161
+ || rows.length !== 1 || hybridDigest(JSON.parse(rows[0].payload_json)) !== hybridDigest({ intent, sha256: copy.sha256 }))
162
+ refuse("copy_custody_changed");
163
+ };
164
+ return { root, copy, route, assertCustody };
165
+ }
@@ -0,0 +1,75 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { createHash } from "node:crypto";
4
+ import { parse as parseYaml } from "yaml";
5
+ import { AppError } from "../shared/errors.js";
6
+ import { ObservedMemorySources } from "./memory-source-observations.js";
7
+ import { memorySourceKey } from "./memory-stage-results.js";
8
+ import { prepareVnextSpecifyStart } from "./vnext-specify.js";
9
+ import { loadVnextWorkspacePolicy } from "./vnext-workspace-policy.js";
10
+ import { hybridDigest } from "./hybrid-contracts.js";
11
+ const identity = [".memory-bank/index.md", ".memory-bank/structure.md", ".memory-bank/project-policy.md"];
12
+ function refuse(reason) {
13
+ throw new AppError("memory_normal_flow_entry_invalid", "Ordinary SDLC entry cannot be prepared from initialized memory", 2, { reason, effect: "no_effect" });
14
+ }
15
+ /** Real ordinary-entry preparation only. No launch, protocol, Work, Session,
16
+ * provider, command execution or runtime receipt is created. Callers still
17
+ * need independent semantic review, selected pack/tools and integration. */
18
+ export function observeMemoryNormalFlowEntry(context, projectRoot) {
19
+ if (context.db.isOwnedWriteTransaction?.())
20
+ refuse("preparation_outside_writer_required");
21
+ if (typeof projectRoot !== "string" || !path.isAbsolute(projectRoot))
22
+ refuse("absolute_project_root_required");
23
+ const root = fs.realpathSync(projectRoot);
24
+ const paths = [...identity, ".memory-bank/mbb/index.md", ".memory-bank/dd-flow/flow-contract.json",
25
+ ".memory-bank/dd-flow/project-execution.json", ".memory-bank/dd-flow/project-workspace.json",
26
+ ".memory-bank/dd-flow/vnext/specify.md"];
27
+ for (const name of ["mb-sdlc-vnext-specify.json", "mb-sdlc-vnext-protocolize.json"]) {
28
+ const logical = `.memory-bank/dd-flow/vnext/${name}`;
29
+ try {
30
+ fs.lstatSync(path.join(root, logical));
31
+ paths.push(logical);
32
+ }
33
+ catch (error) {
34
+ if (error.code !== "ENOENT")
35
+ throw error;
36
+ }
37
+ }
38
+ const observe = (selected) => ObservedMemorySources.capture({ project: root }, selected.map(path => ({ root: "project", path })));
39
+ const before = observe(paths);
40
+ for (const logical of identity) {
41
+ const text = before.bytes({ root: "project", path: logical }).toString("utf8");
42
+ if (!text.startsWith("---\n") && !text.startsWith("---\r\n"))
43
+ refuse("identity_frontmatter_required");
44
+ const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
45
+ if (!match)
46
+ refuse("identity_frontmatter_required");
47
+ const header = parseYaml(match[1]);
48
+ if (!header || typeof header !== "object" || Array.isArray(header))
49
+ refuse("identity_frontmatter_required");
50
+ }
51
+ // This diagnostic intake is never persisted or dispatched as a user task.
52
+ const prepared = prepareVnextSpecifyStart(context, { projectRoot: root,
53
+ intakeMarkdown: "Internal ordinary-entry readiness preparation; do not launch a RUN.", slug: "memory-readiness" });
54
+ const policy = loadVnextWorkspacePolicy(root), profile = prepared.start?.executionProfile;
55
+ if (!profile || prepared.preflight.ok !== true || prepared.start?.projectRoot !== root)
56
+ refuse("ordinary_preparation_incomplete");
57
+ const policyPath = profile.settings.code_bootstrap?.policy_ref;
58
+ if (policyPath !== undefined && (typeof policyPath !== "string" || !policyPath.startsWith(".memory-bank/") || policyPath.includes("\\")
59
+ || policyPath.includes("\0") || policyPath.split("/").some(segment => !segment || segment === "." || segment === "..")))
60
+ refuse("bootstrap_policy_reference_required");
61
+ const selected = [...new Set([...paths, ...(policyPath === undefined ? [] : [policyPath]), ...prepared.grounding.map(item => item.source)])].sort();
62
+ const observed = observe(selected), hashes = observed.hashes();
63
+ before.revalidate();
64
+ if (hashes.get(memorySourceKey("project", ".memory-bank/dd-flow/project-execution.json")) !== profile.source_checksum)
65
+ refuse("ordinary_profile_changed");
66
+ observed.revalidate();
67
+ return { schema_id: "dd-flow/memory-normal-flow-entry-observation@1", project_root: root,
68
+ operation: "stage.start.bootstrap.specify", runtime_state: "not_created", model_access: "unknown",
69
+ source_sha256: observed.sha256, sources: selected.map(path => ({ root: "project", path,
70
+ sha256: hashes.get(memorySourceKey("project", path)) })),
71
+ profile_sha256: profile.source_checksum, execution_sha256: hybridDigest({ settings: profile.settings,
72
+ profiles: profile.agent_profiles ?? null, operational_decision: profile.operational_decision ?? null }),
73
+ template_sha256: createHash("sha256").update(prepared.template).digest("hex"),
74
+ workspace_policy: policy, handoff: prepared.handoff };
75
+ }
@@ -0,0 +1,112 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { spawnSync } from "node:child_process";
4
+ import { isDeepStrictEqual } from "node:util";
5
+ import { AppError } from "../shared/errors.js";
6
+ import { readOperatorProfiles, resolveOperatorProfile } from "./operator-profiles.js";
7
+ import { validateVnextExecutionProfile } from "./vnext-execution-profile.js";
8
+ import { loadVnextWorkspacePolicy } from "./vnext-workspace-policy.js";
9
+ import { readMemoryInitGitPolicy } from "./memory-init-git-policy.js";
10
+ export const ordinaryConfigurationPaths = [".memory-bank/dd-flow/project-execution.json", ".memory-bank/dd-flow/project-workspace.json"];
11
+ function gitObservation(context, workspace, args) {
12
+ const env = Object.fromEntries(Object.entries(context.env ?? process.env).filter(([key]) => !key.startsWith("GIT_")));
13
+ const result = spawnSync("git", ["-C", workspace, ...args], { env: { ...env, GIT_OPTIONAL_LOCKS: "0" }, encoding: "utf8", timeout: 10000, maxBuffer: 65536 });
14
+ return result.status === 0 ? result.stdout.trim() : null;
15
+ }
16
+ function retainedUnbornBranch(context, workspace, scope) {
17
+ if (!scope || scope.projectRoot !== workspace || scope.workspaceRoot !== workspace)
18
+ return null;
19
+ const policy = readMemoryInitGitPolicy(context, scope);
20
+ if (!policy || policy.initial_head !== null || policy.route !== "integration_branch_direct")
21
+ return null;
22
+ const git = (args) => gitObservation(context, workspace, args), common = git(["rev-parse", "--git-common-dir"]);
23
+ if (!common || fs.realpathSync(path.resolve(workspace, common)) !== policy.repository
24
+ || git(["symbolic-ref", "--quiet", "--short", "HEAD"]) !== policy.workspace_branch
25
+ || policy.workspace_branch !== policy.integration_branch || git(["rev-parse", "--verify", "HEAD"]) !== null
26
+ || git(["for-each-ref", "--format=%(refname)", "refs/heads/"]) !== "")
27
+ return null;
28
+ return policy.integration_branch;
29
+ }
30
+ /** Project-owned technical defaults only; never grants authority to a future task. */
31
+ export function prepareMemoryOrdinaryDefaults(context, workspace, selectedProfile, scope) {
32
+ const proposals = [], missing = [];
33
+ const existing = ordinaryConfigurationPaths.map(logical => fs.existsSync(path.join(workspace, logical)));
34
+ if (existing[0])
35
+ validateVnextExecutionProfile(JSON.parse(fs.readFileSync(path.join(workspace, ordinaryConfigurationPaths[0]), "utf8")));
36
+ if (existing[1])
37
+ loadVnextWorkspacePolicy(workspace);
38
+ if (!existing[0]) {
39
+ const settings = readOperatorProfiles(context.ddFlowHome);
40
+ let profile;
41
+ try {
42
+ profile = resolveOperatorProfile(settings, selectedProfile);
43
+ }
44
+ catch {
45
+ if (settings.default_profile)
46
+ profile = resolveOperatorProfile(settings);
47
+ }
48
+ if (!profile)
49
+ missing.push("configured ordinary executor profile");
50
+ else {
51
+ const value = { schema_id: "dd-flow/project-execution@3", stage_session_mode: "new_session", plan_review_mode: "auto", code_review_mode: "auto",
52
+ merge_mode: "server", merge_delivery: { strategy: "local" }, merge_cleanup: { source: "retain" }, stop_target: "merge_completed",
53
+ execution: { agent_profile_id: profile.id, delegation: { mode: "external", max_parallel: 1 } } };
54
+ validateVnextExecutionProfile(value);
55
+ proposals.push({ path: ordinaryConfigurationPaths[0], value });
56
+ }
57
+ }
58
+ let reason = "existing_valid_project_configuration";
59
+ if (!existing[1]) {
60
+ const git = (args) => gitObservation(context, workspace, args);
61
+ const remote = git(["symbolic-ref", "--quiet", "refs/remotes/origin/HEAD"]);
62
+ const branches = git(["for-each-ref", "--format=%(refname:short)", "refs/heads/"])?.split("\n").filter(Boolean) ?? [];
63
+ const unborn = !remote && !branches.length ? retainedUnbornBranch(context, workspace, scope) : null;
64
+ const branch = remote?.startsWith("refs/remotes/origin/") ? remote.slice("refs/remotes/origin/".length) : branches.length === 1 ? branches[0] : unborn;
65
+ reason = remote ? "verified_origin_head" : unborn ? "retained_unborn_init_branch_technical_default" : branch ? "verified_single_local_branch_technical_default" : "integration_branch_choice_required";
66
+ if (!branch || !unborn && !git(["rev-parse", "--verify", `${remote ? `refs/remotes/origin/${branch}` : `refs/heads/${branch}`}^{commit}`]))
67
+ missing.push("ordinary integration branch (multiple or unavailable candidates)");
68
+ else {
69
+ const contractFile = path.join(workspace, ".memory-bank/dd-flow/flow-contract.json");
70
+ const contract = fs.existsSync(contractFile) ? JSON.parse(fs.readFileSync(contractFile, "utf8")) : null;
71
+ const template = contract?.workspace?.feature_branch_template;
72
+ if (typeof template !== "string" || !template.includes("<RUN>"))
73
+ missing.push("ordinary feature branch template from selected flow contract");
74
+ else
75
+ proposals.push({ path: ordinaryConfigurationPaths[1], value: { schema_id: "dd-flow/project-workspace@1", workspace: {
76
+ route: "feature_worktree", integration_branch: branch, feature_branch_template: template, provision_stage: "protocolize_start"
77
+ } } });
78
+ }
79
+ }
80
+ return { proposals, preserved_paths: ordinaryConfigurationPaths.filter((_, index) => existing[index]), required_paths: ordinaryConfigurationPaths.filter((_, index) => !existing[index]), missing, reason };
81
+ }
82
+ /** Existing compose output custody selects these files; this checks their executable meaning. */
83
+ export function assertMemoryOrdinaryConfigurationOutputs(context, workspace, defaults, artifacts, scope) {
84
+ for (const logical of defaults.required_paths)
85
+ if (!artifacts.some(artifact => artifact.root === "workspace" && artifact.path === logical)) {
86
+ throw new AppError("memory_stage_result_invalid", "Compose must retain each required ordinary configuration as an accepted Work output", 2, { phase: "prepare", effect: "no_effect", recoverable: true, reason: "ordinary_configuration_output_missing", path: logical });
87
+ }
88
+ const values = new Map(ordinaryConfigurationPaths.map(logical => [logical, JSON.parse(fs.readFileSync(path.join(workspace, logical), "utf8"))]));
89
+ const profile = validateVnextExecutionProfile(values.get(ordinaryConfigurationPaths[0]));
90
+ const policy = loadVnextWorkspacePolicy(workspace);
91
+ if (profile.execution)
92
+ resolveOperatorProfile(readOperatorProfiles(context.ddFlowHome), profile.execution.agent_profile_id);
93
+ for (const item of defaults.proposals)
94
+ if (!isDeepStrictEqual(values.get(item.path), item.value)) {
95
+ throw new AppError("memory_stage_result_invalid", "Compose changed supplied technical defaults", 2, { phase: "prepare", effect: "no_effect", reason: "ordinary_configuration_changed", path: item.path });
96
+ }
97
+ const branch = policy.workspace.integration_branch;
98
+ const exists = gitObservation(context, workspace, ["rev-parse", "--verify", `refs/heads/${branch}^{commit}`]);
99
+ const remote = exists ? null : gitObservation(context, workspace, ["rev-parse", "--verify", `refs/remotes/origin/${branch}^{commit}`]);
100
+ if (!exists && !remote && retainedUnbornBranch(context, workspace, scope) !== branch)
101
+ throw new AppError("memory_stage_result_invalid", "Ordinary integration branch is not an existing repository branch", 2, { phase: "prepare", effect: "no_effect", reason: "ordinary_integration_branch_unavailable" });
102
+ }
103
+ export function assertMemoryOrdinaryConfigurationCoverage(value, defaults) {
104
+ const plan = value;
105
+ if (plan.details?.works?.some(work => work.write_scopes.some(scope => scope.root === "workspace" && defaults.preserved_paths.includes(scope.path)))) {
106
+ throw new AppError("memory_stage_result_invalid", "Fresh init preserves valid existing ordinary configuration; remove that configuration write scope", 2, { phase: "prepare", effect: "no_effect", recoverable: true, reason: "existing_ordinary_configuration_write" });
107
+ }
108
+ for (const logical of defaults.required_paths)
109
+ if (!plan.details?.works?.some(work => work.unit_ids.length && work.write_scopes.some(scope => scope.root === "workspace" && scope.path === logical))) {
110
+ throw new AppError("memory_stage_result_invalid", "Compose must assign the missing ordinary configuration to a reviewed unit and an exact write scope", 2, { phase: "prepare", effect: "no_effect", recoverable: true, reason: "ordinary_configuration_unassigned", path: logical });
111
+ }
112
+ }