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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (670) hide show
  1. package/CHANGELOG.md +959 -0
  2. package/README.md +139 -10
  3. package/dist/build-info.json +8 -8
  4. package/dist/cli/argument-values.js +38 -0
  5. package/dist/cli/command-inputs.js +417 -0
  6. package/dist/cli/command-metadata.js +303 -0
  7. package/dist/cli/command-option-descriptions.js +192 -0
  8. package/dist/cli/completion-cli.js +70 -0
  9. package/dist/cli/completion.js +57 -0
  10. package/dist/cli/delivery.js +108 -0
  11. package/dist/cli/diagnostic-invocation.js +62 -0
  12. package/dist/cli/diagnostic.js +131 -0
  13. package/dist/cli/error-output.js +62 -0
  14. package/dist/cli/executor-onboarding.js +76 -0
  15. package/dist/cli/flows.js +29 -0
  16. package/dist/cli/harnesses.js +84 -0
  17. package/dist/cli/help.js +521 -19
  18. package/dist/cli/hook-ingress.js +89 -0
  19. package/dist/cli/input-preparation.js +193 -0
  20. package/dist/cli/interactive-invocation.js +33 -0
  21. package/dist/cli/interactive.js +114 -0
  22. package/dist/cli/memory-fix-invocation.js +52 -0
  23. package/dist/cli/memory-fix.js +100 -0
  24. package/dist/cli/memory-flow-admission.js +54 -0
  25. package/dist/cli/memory-init-invocation.js +85 -0
  26. package/dist/cli/memory-init.js +250 -0
  27. package/dist/cli/memory-storage-admission.js +54 -0
  28. package/dist/cli/memory-storage-qualification.js +105 -0
  29. package/dist/cli/memory-storage-transition.js +123 -0
  30. package/dist/cli/memory-upgrade.js +189 -0
  31. package/dist/cli/models.js +39 -0
  32. package/dist/cli/native-hook-ingress.js +94 -0
  33. package/dist/cli/native-hook-preparation.js +82 -0
  34. package/dist/cli/operator-profiles.js +61 -0
  35. package/dist/cli/output-options.js +35 -0
  36. package/dist/cli/response-file.js +72 -0
  37. package/dist/cli/run-cli.js +2020 -555
  38. package/dist/cli/runtime-maintenance-diagnostics.js +46 -0
  39. package/dist/cli/runtime-maintenance-ingress.js +52 -0
  40. package/dist/cli/runtime-process.js +153 -0
  41. package/dist/cli/setup.js +150 -0
  42. package/dist/cli.js +103 -2
  43. package/dist/domain/delivery-flows.js +8 -0
  44. package/dist/domain/diagnostic-aspects.js +103 -0
  45. package/dist/domain/diagnostic-flows.js +8 -0
  46. package/dist/domain/distill-flow.js +20 -0
  47. package/dist/domain/interactive-flow.js +1 -0
  48. package/dist/domain/memory-fix-flow.js +2 -0
  49. package/dist/domain/review-fix-flow.js +2 -0
  50. package/dist/domain/source-snapshot-flows.js +4 -0
  51. package/dist/domain/stage-catalog.js +1 -1
  52. package/dist/domain/stage-handler-identities.js +28 -0
  53. package/dist/harness-runtime/DD-ZCODE.md +112 -0
  54. package/dist/harness-runtime/OPENCODE-LICENSE.txt +24 -0
  55. package/dist/harness-runtime/bin/dd-agy.mjs +71 -0
  56. package/dist/harness-runtime/bin/dd-codex.mjs +27 -0
  57. package/dist/harness-runtime/bin/dd-droid.mjs +34 -0
  58. package/dist/harness-runtime/bin/dd-grok.mjs +50 -0
  59. package/dist/harness-runtime/bin/dd-opencode.mjs +22 -0
  60. package/dist/harness-runtime/bin/dd-zcode.mjs +95 -0
  61. package/dist/harness-runtime/lib/adapter-timeouts.d.mts +5 -0
  62. package/dist/harness-runtime/lib/adapter-timeouts.mjs +34 -0
  63. package/dist/harness-runtime/lib/agy-error-boundary.mjs +87 -0
  64. package/dist/harness-runtime/lib/agy-hooks.d.mts +1 -0
  65. package/dist/harness-runtime/lib/agy-hooks.mjs +9 -0
  66. package/dist/harness-runtime/lib/agy-native-inspection.mjs +225 -0
  67. package/dist/harness-runtime/lib/agy-native-inventory.mjs +19 -0
  68. package/dist/harness-runtime/lib/agy-native_pb.js +117 -0
  69. package/dist/harness-runtime/lib/agy-terminal-envelope.mjs +74 -0
  70. package/dist/harness-runtime/lib/agy-transcript-stream.mjs +54 -0
  71. package/dist/harness-runtime/lib/daemon-observation.d.mts +3 -0
  72. package/dist/harness-runtime/lib/daemon-observation.mjs +171 -0
  73. package/dist/harness-runtime/lib/daemon-operations.d.mts +2 -0
  74. package/dist/harness-runtime/lib/daemon-operations.mjs +512 -0
  75. package/dist/harness-runtime/lib/dd-agy-daemon.d.mts +7 -0
  76. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +1362 -0
  77. package/dist/harness-runtime/lib/dd-agy.mjs +105 -0
  78. package/dist/harness-runtime/lib/dd-codex-daemon.d.mts +1 -0
  79. package/dist/harness-runtime/lib/dd-codex-daemon.mjs +271 -0
  80. package/dist/harness-runtime/lib/dd-codex.d.mts +1 -0
  81. package/dist/harness-runtime/lib/dd-codex.mjs +986 -0
  82. package/dist/harness-runtime/lib/dd-droid-daemon.mjs +155 -0
  83. package/dist/harness-runtime/lib/dd-droid.mjs +739 -0
  84. package/dist/harness-runtime/lib/dd-grok-daemon.d.mts +1 -0
  85. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +667 -0
  86. package/dist/harness-runtime/lib/dd-grok.mjs +182 -0
  87. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +772 -0
  88. package/dist/harness-runtime/lib/dd-opencode.mjs +411 -0
  89. package/dist/harness-runtime/lib/dd-zcode-daemon.d.mts +1 -0
  90. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +845 -0
  91. package/dist/harness-runtime/lib/dd-zcode.mjs +1239 -0
  92. package/dist/harness-runtime/lib/delegation-instructions.d.mts +16 -0
  93. package/dist/harness-runtime/lib/delegation-instructions.mjs +179 -0
  94. package/dist/harness-runtime/lib/delivery-command.mjs +84 -0
  95. package/dist/harness-runtime/lib/dispatch-fence.mjs +14 -0
  96. package/dist/harness-runtime/lib/driver-recovery.mjs +121 -0
  97. package/dist/harness-runtime/lib/droid-observation.mjs +70 -0
  98. package/dist/harness-runtime/lib/entity-references.d.mts +2 -0
  99. package/dist/harness-runtime/lib/entity-references.mjs +9 -0
  100. package/dist/harness-runtime/lib/lease-renewal.d.mts +8 -0
  101. package/dist/harness-runtime/lib/lease-renewal.mjs +37 -0
  102. package/dist/harness-runtime/lib/lifecycle-command.d.mts +20 -0
  103. package/dist/harness-runtime/lib/lifecycle-command.mjs +273 -0
  104. package/dist/harness-runtime/lib/lifecycle-contract.d.mts +11 -0
  105. package/dist/harness-runtime/lib/lifecycle-contract.mjs +20 -0
  106. package/dist/harness-runtime/lib/managed-daemon.d.mts +16 -0
  107. package/dist/harness-runtime/lib/managed-daemon.mjs +698 -0
  108. package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
  109. package/dist/harness-runtime/lib/model-observations.mjs +113 -0
  110. package/dist/harness-runtime/lib/native-children.d.mts +34 -0
  111. package/dist/harness-runtime/lib/native-children.mjs +265 -0
  112. package/dist/harness-runtime/lib/native-hook-command.d.mts +8 -0
  113. package/dist/harness-runtime/lib/native-hook-command.mjs +306 -0
  114. package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
  115. package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
  116. package/dist/harness-runtime/lib/native-streams.mjs +38 -0
  117. package/dist/harness-runtime/lib/observation-clock.d.mts +18 -0
  118. package/dist/harness-runtime/lib/observation-clock.mjs +95 -0
  119. package/dist/harness-runtime/lib/opencode-plugin.mjs +112 -0
  120. package/dist/harness-runtime/lib/operation-context.mjs +5 -0
  121. package/dist/harness-runtime/lib/operation-errors.d.mts +16 -0
  122. package/dist/harness-runtime/lib/operation-errors.mjs +140 -0
  123. package/dist/harness-runtime/lib/operation-progress.d.mts +7 -0
  124. package/dist/harness-runtime/lib/operation-progress.mjs +118 -0
  125. package/dist/harness-runtime/lib/process-json.d.mts +5 -0
  126. package/dist/harness-runtime/lib/process-json.mjs +200 -0
  127. package/dist/harness-runtime/lib/process-snapshot.mjs +10 -0
  128. package/dist/harness-runtime/lib/provider-overload-policy.d.mts +23 -0
  129. package/dist/harness-runtime/lib/provider-overload-policy.mjs +242 -0
  130. package/dist/harness-runtime/lib/runner-events.mjs +202 -0
  131. package/dist/harness-runtime/lib/runner-lock.mjs +42 -0
  132. package/dist/harness-runtime/lib/session-settlement.mjs +30 -0
  133. package/dist/harness-runtime/lib/setup-progress.d.mts +9 -0
  134. package/dist/harness-runtime/lib/setup-progress.mjs +53 -0
  135. package/dist/harness-runtime/lib/tool-observations.d.mts +21 -0
  136. package/dist/harness-runtime/lib/tool-observations.mjs +238 -0
  137. package/dist/harness-runtime/lib/zcode-native-hook-ownership.mjs +109 -0
  138. package/dist/harness-runtime/lib/zcode-usage.mjs +55 -0
  139. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-1y4a697q.js +81 -0
  140. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-2ny4vxct.js +92 -0
  141. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-6mptkzbc.js +0 -0
  142. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-7x67cf1q.js +52 -0
  143. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9rqn6x4v.js +16 -0
  144. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9vdz0zwn.js +1661 -0
  145. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ecs5ftka.js +1466 -0
  146. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-frbwqjmf.js +145 -0
  147. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gne7h7mq.js +50 -0
  148. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gx9wnkzr.js +105 -0
  149. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-m2eywc8w.js +0 -0
  150. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-nwcpakzx.js +12 -0
  151. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-q4g3afnw.js +623 -0
  152. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-qav6mfdz.js +0 -0
  153. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-sxt88q69.js +12 -0
  154. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-t1xa31vm.js +39 -0
  155. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ve4aws36.js +103 -0
  156. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vmytr4q8.js +4 -0
  157. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vt9jbch8.js +36 -0
  158. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vyas3vgt.js +0 -0
  159. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-wjyeq25y.js +30 -0
  160. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-xgnj2w4v.js +20 -0
  161. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-y2etg5bs.js +9 -0
  162. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ydhz1zrh.js +238 -0
  163. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-z6qdwcsf.js +62 -0
  164. package/dist/harness-runtime/vendor/opencode-client/contract.d.ts +1 -0
  165. package/dist/harness-runtime/vendor/opencode-client/contract.js +12 -0
  166. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.d.ts +2806 -0
  167. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.js +0 -0
  168. package/dist/harness-runtime/vendor/opencode-client/effect/api.d.ts +4 -0
  169. package/dist/harness-runtime/vendor/opencode-client/effect/api.js +0 -0
  170. package/dist/harness-runtime/vendor/opencode-client/effect/client.d.ts +2530 -0
  171. package/dist/harness-runtime/vendor/opencode-client/effect/client.js +15 -0
  172. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.d.ts +7 -0
  173. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.js +6 -0
  174. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.d.ts +2529 -0
  175. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.js +8 -0
  176. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.d.ts +2 -0
  177. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.js +12 -0
  178. package/dist/harness-runtime/vendor/opencode-client/effect/index.d.ts +35 -0
  179. package/dist/harness-runtime/vendor/opencode-client/effect/index.js +75 -0
  180. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.d.ts +20 -0
  181. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.js +11 -0
  182. package/dist/harness-runtime/vendor/opencode-client/effect/service.d.ts +90 -0
  183. package/dist/harness-runtime/vendor/opencode-client/effect/service.js +187 -0
  184. package/dist/harness-runtime/vendor/opencode-client/package.json +84 -0
  185. package/dist/harness-runtime/vendor/opencode-client/promise/api.d.ts +21 -0
  186. package/dist/harness-runtime/vendor/opencode-client/promise/api.js +0 -0
  187. package/dist/harness-runtime/vendor/opencode-client/promise/client.d.ts +252 -0
  188. package/dist/harness-runtime/vendor/opencode-client/promise/client.js +14 -0
  189. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.d.ts +8 -0
  190. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.js +6 -0
  191. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.d.ts +259 -0
  192. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.js +7 -0
  193. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.d.ts +3 -0
  194. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.js +79 -0
  195. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.d.ts +8932 -0
  196. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.js +70 -0
  197. package/dist/harness-runtime/vendor/opencode-client/promise/index.d.ts +6 -0
  198. package/dist/harness-runtime/vendor/opencode-client/promise/index.js +83 -0
  199. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.d.ts +32 -0
  200. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.js +7 -0
  201. package/dist/harness-runtime/vendor/opencode-client/promise/service.d.ts +24 -0
  202. package/dist/harness-runtime/vendor/opencode-client/promise/service.js +187 -0
  203. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.d.ts +12 -0
  204. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.js +14 -0
  205. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.d.ts +20 -0
  206. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.js +14 -0
  207. package/dist/harness-runtime/vendor/opencode-client/service-contender.d.ts +37 -0
  208. package/dist/harness-runtime/vendor/opencode-client/service-contender.js +10 -0
  209. package/dist/harness-runtime/vendor/opencode-client/service-probe.d.ts +70 -0
  210. package/dist/harness-runtime/vendor/opencode-client/service-probe.js +16 -0
  211. package/dist/harness-runtime/vendor/opencode-client/service-timing.d.ts +12 -0
  212. package/dist/harness-runtime/vendor/opencode-client/service-timing.js +10 -0
  213. package/dist/harness-runtime/vendor/opencode-client/service-version.d.ts +2 -0
  214. package/dist/harness-runtime/vendor/opencode-client/service-version.js +6 -0
  215. package/dist/harness-runtime/vendor/opencode-client/service.d.ts +52 -0
  216. package/dist/harness-runtime/vendor/opencode-client/service.js +1 -0
  217. package/dist/harness-runtime/vendor/opencode-client/shared-events.d.ts +11 -0
  218. package/dist/harness-runtime/vendor/opencode-client/shared-events.js +8 -0
  219. package/dist/harness-runtime/vendor/opencode-client/solid/connection.d.ts +37 -0
  220. package/dist/harness-runtime/vendor/opencode-client/solid/connection.js +10 -0
  221. package/dist/harness-runtime/vendor/opencode-client/solid/data.d.ts +211 -0
  222. package/dist/harness-runtime/vendor/opencode-client/solid/data.js +18 -0
  223. package/dist/harness-runtime/vendor/opencode-client/solid/index.d.ts +3 -0
  224. package/dist/harness-runtime/vendor/opencode-client/solid/index.js +32 -0
  225. package/dist/harness-runtime/vendor/opencode-client/solid/pty.d.ts +22 -0
  226. package/dist/harness-runtime/vendor/opencode-client/solid/pty.js +8 -0
  227. package/dist/harness-runtime/vendor/opencode-plugin.mjs +3 -0
  228. package/dist/protocol/local-files.js +18 -9
  229. package/dist/runtime/context.js +8 -4
  230. package/dist/schemas/agent-profile.schema.json +1 -1
  231. package/dist/schemas/code-review-decision.schema.json +9 -0
  232. package/dist/schemas/code-review-result.schema.json +1 -1
  233. package/dist/schemas/code-verification.schema.json +7 -5
  234. package/dist/schemas/code-work-batch.schema.json +2 -2
  235. package/dist/schemas/code-work-result.schema.json +2 -1
  236. package/dist/schemas/delivery-stage-result.schema.json +286 -0
  237. package/dist/schemas/diagnostic-stage-result.schema.json +354 -0
  238. package/dist/schemas/diagnostic-work-result.schema.json +296 -0
  239. package/dist/schemas/discovery-result.schema.json +184 -0
  240. package/dist/schemas/distill-stage-result.schema.json +667 -0
  241. package/dist/schemas/distill-work-result.schema.json +428 -0
  242. package/dist/schemas/execution-bundle.schema.json +215 -0
  243. package/dist/schemas/execution-settings.schema.json +162 -0
  244. package/dist/schemas/flow-descriptor.schema.json +54 -0
  245. package/dist/schemas/flow-run.schema.json +29 -0
  246. package/dist/schemas/harness-catalog.schema.json +80 -0
  247. package/dist/schemas/interactive-stage-result.schema.json +47 -0
  248. package/dist/schemas/interactive-work-result.schema.json +63 -0
  249. package/dist/schemas/mb-fix-stage-result.schema.json +93 -0
  250. package/dist/schemas/mb-init-compose-result.schema.json +457 -0
  251. package/dist/schemas/mb-init-discover-result.schema.json +500 -0
  252. package/dist/schemas/mb-init-finish-result.schema.json +422 -0
  253. package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
  254. package/dist/schemas/mb-init-review-result.schema.json +396 -0
  255. package/dist/schemas/mb-init-verify-result.schema.json +391 -0
  256. package/dist/schemas/mb-upgrade-stage-result.schema.json +863 -0
  257. package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
  258. package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
  259. package/dist/schemas/memory-composition-work-result.schema.json +38 -0
  260. package/dist/schemas/memory-repair-work-result.schema.json +56 -0
  261. package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
  262. package/dist/schemas/memory-review-work-result.schema.json +43 -0
  263. package/dist/schemas/model-catalog.schema.json +153 -0
  264. package/dist/schemas/plan-review-decision.schema.json +12 -3
  265. package/dist/schemas/plan-review-result.schema.json +2 -2
  266. package/dist/schemas/profile-settings.schema.json +122 -0
  267. package/dist/schemas/project-flow-pack-manifest.schema.json +2 -2
  268. package/dist/schemas/release-impact.schema.json +3 -3
  269. package/dist/schemas/release-manifest.schema.json +291 -0
  270. package/dist/schemas/review-fix-stage-result.schema.json +210 -0
  271. package/dist/schemas/run-control-receipt.schema.json +119 -0
  272. package/dist/schemas/run-control-request.schema.json +36 -0
  273. package/dist/schemas/run-engine-binding.schema.json +1 -1
  274. package/dist/schemas/stage-start-response.schema.json +4 -0
  275. package/dist/schemas/vnext-protocol-plan.schema.json +3 -3
  276. package/dist/services/accepted-intent.js +139 -0
  277. package/dist/services/assigned-lifecycle.js +382 -0
  278. package/dist/services/branch-context.js +3 -3
  279. package/dist/services/canon.js +54 -15
  280. package/dist/services/check-environment.js +21 -0
  281. package/dist/services/check-runner-evidence.js +344 -0
  282. package/dist/services/check-runner-proof.js +373 -0
  283. package/dist/services/cleanup.js +133 -40
  284. package/dist/services/cli-operation-classifier.js +32 -64
  285. package/dist/services/cli-upgrade-allowlist.js +27 -0
  286. package/dist/services/code-checks.js +1426 -121
  287. package/dist/services/codex-capacity.js +367 -0
  288. package/dist/services/codex-hook-delivery.js +41 -0
  289. package/dist/services/command-context.js +80 -0
  290. package/dist/services/compatibility-preflight.js +16 -3
  291. package/dist/services/config.js +11 -8
  292. package/dist/services/continuation-outcome.js +25 -0
  293. package/dist/services/controller-child-capacity.js +71 -0
  294. package/dist/services/controller-child-observer.js +121 -0
  295. package/dist/services/controller-child-repair.js +117 -0
  296. package/dist/services/controller-execution.js +97 -0
  297. package/dist/services/controller-fanout.js +277 -0
  298. package/dist/services/controller-memory-task.js +45 -0
  299. package/dist/services/controller-memory-worker.js +51 -0
  300. package/dist/services/controller-result-authority.js +127 -0
  301. package/dist/services/controller-work-failure.js +198 -0
  302. package/dist/services/dashboard.js +145 -58
  303. package/dist/services/delivery-access.js +123 -0
  304. package/dist/services/delivery-approval.js +68 -0
  305. package/dist/services/delivery-artifact.js +86 -0
  306. package/dist/services/delivery-checks.js +178 -0
  307. package/dist/services/delivery-execution.js +181 -0
  308. package/dist/services/delivery-intents.js +212 -0
  309. package/dist/services/delivery-operation.js +81 -0
  310. package/dist/services/delivery-policy.js +91 -0
  311. package/dist/services/delivery-procedures.js +43 -0
  312. package/dist/services/delivery-request.js +99 -0
  313. package/dist/services/delivery-result.js +144 -0
  314. package/dist/services/delivery-stage-commands.js +26 -0
  315. package/dist/services/delivery-stage-entry.js +56 -0
  316. package/dist/services/delivery-stage-handlers.js +135 -0
  317. package/dist/services/delivery-stage-results.js +94 -0
  318. package/dist/services/descriptor-coordinator-session.js +37 -0
  319. package/dist/services/descriptor-root-work.js +53 -0
  320. package/dist/services/descriptor-run-settlement.js +107 -0
  321. package/dist/services/descriptor-run-start.js +495 -0
  322. package/dist/services/descriptor-stage-coordinator.js +318 -0
  323. package/dist/services/descriptor-stage-settlement.js +268 -0
  324. package/dist/services/descriptor-stage-start.js +175 -0
  325. package/dist/services/diagnostic-evidence.js +73 -0
  326. package/dist/services/diagnostic-repair-intake.js +123 -0
  327. package/dist/services/diagnostic-repair-source-intake.js +102 -0
  328. package/dist/services/diagnostic-report-publication.js +72 -0
  329. package/dist/services/diagnostic-report.js +97 -0
  330. package/dist/services/diagnostic-run-bundle.js +113 -0
  331. package/dist/services/diagnostic-snapshot.js +159 -0
  332. package/dist/services/diagnostic-stage-handlers.js +109 -0
  333. package/dist/services/diagnostic-stage-results.js +158 -0
  334. package/dist/services/diagnostic-start.js +134 -0
  335. package/dist/services/diagnostic-work-batch.js +34 -0
  336. package/dist/services/diagnostic-work-collection.js +97 -0
  337. package/dist/services/diagnostic-work-registration.js +101 -0
  338. package/dist/services/diagnostic-work-results.js +93 -0
  339. package/dist/services/discovery/agy-discovery.js +2 -0
  340. package/dist/services/discovery/codex-discovery.js +2 -0
  341. package/dist/services/discovery/droid-discovery.js +2 -0
  342. package/dist/services/discovery/grok-discovery.js +2 -0
  343. package/dist/services/discovery/opencode-discovery.js +2 -0
  344. package/dist/services/discovery/static.js +31 -0
  345. package/dist/services/discovery/zcode-discovery.js +2 -0
  346. package/dist/services/distill-document-publication.js +280 -0
  347. package/dist/services/distill-promotion.js +197 -0
  348. package/dist/services/distill-publication-custody.js +162 -0
  349. package/dist/services/distill-stage-handlers.js +249 -0
  350. package/dist/services/distill-stage-results.js +105 -0
  351. package/dist/services/distill-user-inputs.js +4 -0
  352. package/dist/services/distill-work-batch.js +42 -0
  353. package/dist/services/distill-work-collection.js +74 -0
  354. package/dist/services/distill-work-registration.js +93 -0
  355. package/dist/services/distill-work-results.js +98 -0
  356. package/dist/services/engines.js +354 -163
  357. package/dist/services/eval-snapshots.js +1326 -150
  358. package/dist/services/execution-bundles.js +275 -0
  359. package/dist/services/execution-policy.js +185 -0
  360. package/dist/services/executor-onboarding.js +56 -0
  361. package/dist/services/external-work-launch.js +316 -0
  362. package/dist/services/flow-catalog.js +54 -0
  363. package/dist/services/flow-descriptors.js +82 -0
  364. package/dist/services/frozen-engine.js +404 -0
  365. package/dist/services/generic-execution.js +165 -0
  366. package/dist/services/harness-adapter.js +342 -35
  367. package/dist/services/harness-config.js +2 -0
  368. package/dist/services/harness-discovery.js +29 -0
  369. package/dist/services/harness-doctor.js +75 -0
  370. package/dist/services/harness-probe-effects.js +51 -0
  371. package/dist/services/harness-version-probe.js +100 -0
  372. package/dist/services/hook-memory-routing.js +188 -0
  373. package/dist/services/hook-recovery-guard.js +14 -0
  374. package/dist/services/hook-session-observation.js +24 -0
  375. package/dist/services/hooks.js +813 -327
  376. package/dist/services/hybrid-contracts.js +479 -0
  377. package/dist/services/hybrid-digest.js +14 -0
  378. package/dist/services/ids.js +29 -1
  379. package/dist/services/installation-lock.js +95 -0
  380. package/dist/services/installed-flow-source.js +261 -0
  381. package/dist/services/interactive-attached-session.js +215 -0
  382. package/dist/services/interactive-baseline-custody.js +54 -0
  383. package/dist/services/interactive-before-versions.js +148 -0
  384. package/dist/services/interactive-bundle-data.js +85 -0
  385. package/dist/services/interactive-checks.js +179 -0
  386. package/dist/services/interactive-execution.js +33 -0
  387. package/dist/services/interactive-finish-integration.js +236 -0
  388. package/dist/services/interactive-git-baseline.js +230 -0
  389. package/dist/services/interactive-git-dispatch.js +278 -0
  390. package/dist/services/interactive-input-delivery.js +82 -0
  391. package/dist/services/interactive-mutation-scope.js +231 -0
  392. package/dist/services/interactive-request.js +287 -0
  393. package/dist/services/interactive-run-bundle.js +109 -0
  394. package/dist/services/interactive-stage-entry.js +41 -0
  395. package/dist/services/interactive-stage-handlers.js +289 -0
  396. package/dist/services/interactive-stage-observation.js +136 -0
  397. package/dist/services/interactive-stage-results.js +111 -0
  398. package/dist/services/interactive-user-inputs.js +142 -0
  399. package/dist/services/interactive-work-batch.js +43 -0
  400. package/dist/services/interactive-work-collection.js +119 -0
  401. package/dist/services/interactive-work-completion.js +180 -0
  402. package/dist/services/interactive-work-context.js +249 -0
  403. package/dist/services/interactive-work-history.js +112 -0
  404. package/dist/services/interactive-work-registration.js +124 -0
  405. package/dist/services/interactive-work-results.js +115 -0
  406. package/dist/services/interactive-work-start.js +155 -0
  407. package/dist/services/lanes.js +78 -65
  408. package/dist/services/lifecycle-command.js +1 -288
  409. package/dist/services/lifecycle-contract.js +1 -0
  410. package/dist/services/lifecycle-invocations.js +2549 -0
  411. package/dist/services/managed-daemon-binding.js +129 -0
  412. package/dist/services/managed-lease-monitor.js +133 -0
  413. package/dist/services/managed-processes.js +449 -69
  414. package/dist/services/memory-accepted-composition.js +78 -0
  415. package/dist/services/memory-baseline-preservation.js +65 -0
  416. package/dist/services/memory-completed-correction-wave.js +328 -0
  417. package/dist/services/memory-compose-handler.js +380 -0
  418. package/dist/services/memory-composition-acceptance.js +375 -0
  419. package/dist/services/memory-composition-graph.js +165 -0
  420. package/dist/services/memory-composition-registration.js +161 -0
  421. package/dist/services/memory-composition-work-custody.js +156 -0
  422. package/dist/services/memory-composition-work-results.js +108 -0
  423. package/dist/services/memory-corrected-review-acceptance.js +129 -0
  424. package/dist/services/memory-corrected-review-batch.js +37 -0
  425. package/dist/services/memory-corrected-review-findings.js +108 -0
  426. package/dist/services/memory-corrected-review-inputs.js +215 -0
  427. package/dist/services/memory-corrected-review-projection.js +78 -0
  428. package/dist/services/memory-corrected-review-receipt.js +178 -0
  429. package/dist/services/memory-corrected-review-registration.js +192 -0
  430. package/dist/services/memory-correction-check-receipt.js +235 -0
  431. package/dist/services/memory-correction-input-owner.js +6 -0
  432. package/dist/services/memory-custody-snapshot.js +36 -0
  433. package/dist/services/memory-discover-handler.js +104 -0
  434. package/dist/services/memory-finish-evidence.js +457 -0
  435. package/dist/services/memory-finish-handler.js +229 -0
  436. package/dist/services/memory-finish-integration.js +491 -0
  437. package/dist/services/memory-finish-readiness.js +169 -0
  438. package/dist/services/memory-fix-finish-integration.js +129 -0
  439. package/dist/services/memory-fix-git-dispatch.js +139 -0
  440. package/dist/services/memory-fix-intake-custody.js +11 -0
  441. package/dist/services/memory-fix-intake-settlement.js +127 -0
  442. package/dist/services/memory-fix-publication.js +196 -0
  443. package/dist/services/memory-fix-repair-admission.js +116 -0
  444. package/dist/services/memory-fix-request.js +141 -0
  445. package/dist/services/memory-fix-run-bundle.js +83 -0
  446. package/dist/services/memory-fix-scope.js +78 -0
  447. package/dist/services/memory-fix-sources.js +85 -0
  448. package/dist/services/memory-fix-stage-entry.js +24 -0
  449. package/dist/services/memory-fix-stage-handlers.js +282 -0
  450. package/dist/services/memory-fix-stage-results.js +106 -0
  451. package/dist/services/memory-fix-workspace.js +127 -0
  452. package/dist/services/memory-flow-user-inputs.js +88 -0
  453. package/dist/services/memory-git-integration.js +220 -0
  454. package/dist/services/memory-historical-corrected-review.js +212 -0
  455. package/dist/services/memory-historical-original-review.js +143 -0
  456. package/dist/services/memory-historical-repair-registration.js +105 -0
  457. package/dist/services/memory-historical-second-review.js +147 -0
  458. package/dist/services/memory-init-bootstrap-readiness.js +210 -0
  459. package/dist/services/memory-init-contexts.js +181 -0
  460. package/dist/services/memory-init-controller-start.js +119 -0
  461. package/dist/services/memory-init-engine-release.js +223 -0
  462. package/dist/services/memory-init-git-policy.js +165 -0
  463. package/dist/services/memory-init-lint-capability.js +203 -0
  464. package/dist/services/memory-init-native-capacity.js +309 -0
  465. package/dist/services/memory-init-preflight.js +334 -0
  466. package/dist/services/memory-init-project-bootstrap.js +599 -0
  467. package/dist/services/memory-init-request-candidate.js +213 -0
  468. package/dist/services/memory-init-request-input.js +82 -0
  469. package/dist/services/memory-init-resource-storage.js +125 -0
  470. package/dist/services/memory-init-run-allocation.js +81 -0
  471. package/dist/services/memory-init-run-bundle.js +135 -0
  472. package/dist/services/memory-init-start.js +181 -0
  473. package/dist/services/memory-init-startup-custody.js +80 -0
  474. package/dist/services/memory-init-startup-input.js +240 -0
  475. package/dist/services/memory-init-storage.js +91 -0
  476. package/dist/services/memory-init-stores.js +359 -0
  477. package/dist/services/memory-init-worktrunk-capability.js +174 -0
  478. package/dist/services/memory-layer-publication.js +611 -0
  479. package/dist/services/memory-layer.js +225 -0
  480. package/dist/services/memory-lint-config.js +194 -0
  481. package/dist/services/memory-native-review-copy.js +127 -0
  482. package/dist/services/memory-normal-flow-entry.js +87 -0
  483. package/dist/services/memory-ordinary-defaults.js +129 -0
  484. package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
  485. package/dist/services/memory-preflight-handler.js +274 -0
  486. package/dist/services/memory-repair-current-view.js +299 -0
  487. package/dist/services/memory-repair-document-delta.js +489 -0
  488. package/dist/services/memory-repair-history.js +496 -0
  489. package/dist/services/memory-repair-physical-binding.js +194 -0
  490. package/dist/services/memory-repair-publication-files.js +152 -0
  491. package/dist/services/memory-repair-publication-intent.js +27 -0
  492. package/dist/services/memory-repair-publication-plan.js +162 -0
  493. package/dist/services/memory-repair-publication-source.js +225 -0
  494. package/dist/services/memory-repair-publication.js +795 -0
  495. package/dist/services/memory-repair-registration.js +240 -0
  496. package/dist/services/memory-repair-work-baseline.js +415 -0
  497. package/dist/services/memory-repair-work-completion.js +117 -0
  498. package/dist/services/memory-repair-work-custody.js +73 -0
  499. package/dist/services/memory-repair-work-results.js +108 -0
  500. package/dist/services/memory-repair-workspace.js +261 -0
  501. package/dist/services/memory-repair-writer-copy.js +736 -0
  502. package/dist/services/memory-result-binding.js +239 -0
  503. package/dist/services/memory-retained-review-authority.js +138 -0
  504. package/dist/services/memory-retained-review-results.js +70 -0
  505. package/dist/services/memory-retained-second-baseline.js +102 -0
  506. package/dist/services/memory-retained-second-repairs.js +162 -0
  507. package/dist/services/memory-review-acceptance.js +214 -0
  508. package/dist/services/memory-review-correction-plan.js +206 -0
  509. package/dist/services/memory-review-handler.js +585 -0
  510. package/dist/services/memory-review-inputs.js +246 -0
  511. package/dist/services/memory-review-limits.js +10 -0
  512. package/dist/services/memory-review-receipt.js +180 -0
  513. package/dist/services/memory-review-registration.js +117 -0
  514. package/dist/services/memory-review-work-custody.js +126 -0
  515. package/dist/services/memory-review-work-input.js +91 -0
  516. package/dist/services/memory-review-work-results.js +95 -0
  517. package/dist/services/memory-second-corrected-review-inputs.js +167 -0
  518. package/dist/services/memory-second-correction-plan.js +77 -0
  519. package/dist/services/memory-second-repair-baseline.js +91 -0
  520. package/dist/services/memory-second-repair-launch.js +614 -0
  521. package/dist/services/memory-second-repair-registration.js +88 -0
  522. package/dist/services/memory-second-repair-source.js +187 -0
  523. package/dist/services/memory-second-review-acceptance.js +115 -0
  524. package/dist/services/memory-source-observations.js +117 -0
  525. package/dist/services/memory-stage-dispatch.js +65 -0
  526. package/dist/services/memory-stage-results.js +290 -0
  527. package/dist/services/memory-tool-probe.js +25 -0
  528. package/dist/services/memory-upgrade-analysis-handler.js +243 -0
  529. package/dist/services/memory-upgrade-bootstrap-readiness.js +251 -0
  530. package/dist/services/memory-upgrade-evidence.js +100 -0
  531. package/dist/services/memory-upgrade-inventory.js +442 -0
  532. package/dist/services/memory-upgrade-publication-custody.js +73 -0
  533. package/dist/services/memory-upgrade-publication.js +413 -0
  534. package/dist/services/memory-upgrade-selection.js +430 -0
  535. package/dist/services/memory-upgrade-start.js +60 -0
  536. package/dist/services/memory-upgrade-storage-readiness.js +340 -0
  537. package/dist/services/memory-verification-acceptance.js +156 -0
  538. package/dist/services/memory-verification-checks.js +317 -0
  539. package/dist/services/memory-verification-receipt.js +160 -0
  540. package/dist/services/memory-verify-handler.js +137 -0
  541. package/dist/services/memory-work-result-json.js +12 -0
  542. package/dist/services/memory-work-result-preparation.js +64 -0
  543. package/dist/services/merge-queue.js +228 -149
  544. package/dist/services/merge-server.js +163 -35
  545. package/dist/services/migrations.js +164 -114
  546. package/dist/services/model-catalog.js +109 -0
  547. package/dist/services/model-discovery.js +46 -0
  548. package/dist/services/native-daemon-history.js +50 -0
  549. package/dist/services/native-session-control.js +39 -0
  550. package/dist/services/operator-profiles.js +236 -0
  551. package/dist/services/physical-startup.js +45 -0
  552. package/dist/services/plan-runtime.js +26 -11
  553. package/dist/services/plans.js +28 -25
  554. package/dist/services/project-flow-source.js +195 -0
  555. package/dist/services/project-git-integration.js +92 -0
  556. package/dist/services/project-registry.js +97 -0
  557. package/dist/services/project-summary.js +1 -1
  558. package/dist/services/projects.js +17 -87
  559. package/dist/services/prompt-delivery.js +71 -0
  560. package/dist/services/prompts.js +28 -17
  561. package/dist/services/protocols.js +163 -87
  562. package/dist/services/provider-capacity.js +463 -0
  563. package/dist/services/recovery-observation-budget.js +121 -0
  564. package/dist/services/recovery-snapshot-database.js +588 -0
  565. package/dist/services/release-archive-producer.js +52 -0
  566. package/dist/services/release-archive.js +143 -0
  567. package/dist/services/release-cache.js +150 -0
  568. package/dist/services/release-compatibility.js +18 -0
  569. package/dist/services/release-download.js +67 -0
  570. package/dist/services/release-envelope.js +104 -0
  571. package/dist/services/release-manifest.js +45 -0
  572. package/dist/services/release-payload.js +114 -0
  573. package/dist/services/release-producer.js +63 -0
  574. package/dist/services/release-provenance.js +160 -0
  575. package/dist/services/release-registry.js +66 -0
  576. package/dist/services/release-source.js +194 -0
  577. package/dist/services/repair-intents.js +29 -0
  578. package/dist/services/repair-receipt.js +13 -0
  579. package/dist/services/retained-native-hook.js +274 -0
  580. package/dist/services/review-copy.js +165 -0
  581. package/dist/services/review-deferral.js +23 -0
  582. package/dist/services/review-fix-handoff.js +82 -0
  583. package/dist/services/review-fix-intake-custody.js +17 -0
  584. package/dist/services/review-fix-stage-entry.js +43 -0
  585. package/dist/services/review-fix-stage-handlers.js +176 -0
  586. package/dist/services/review-fix-stage-results.js +86 -0
  587. package/dist/services/run-control-receipt.js +56 -0
  588. package/dist/services/run-control-worker.js +469 -0
  589. package/dist/services/run-control.js +1109 -0
  590. package/dist/services/run-controller-adapter.js +434 -0
  591. package/dist/services/run-controller-capture.js +186 -0
  592. package/dist/services/run-controller-process.js +226 -0
  593. package/dist/services/run-controller-recovery.js +335 -0
  594. package/dist/services/run-controller-state.js +106 -0
  595. package/dist/services/run-controller.js +1717 -0
  596. package/dist/services/run-engine-bindings.js +1 -1
  597. package/dist/services/run-fork.js +147 -0
  598. package/dist/services/run-health.js +149 -0
  599. package/dist/services/run-observations.js +152 -0
  600. package/dist/services/run-projection.js +22 -64
  601. package/dist/services/run-recovery-guard.js +107 -0
  602. package/dist/services/run-recovery-runtime.js +112 -0
  603. package/dist/services/run-recovery.js +485 -0
  604. package/dist/services/run-start-custody.js +189 -0
  605. package/dist/services/run-timeline.js +59 -0
  606. package/dist/services/runs.js +996 -271
  607. package/dist/services/runtime-budget.js +446 -0
  608. package/dist/services/runtime-command.js +43 -0
  609. package/dist/services/runtime-scope-capture.js +52 -0
  610. package/dist/services/runtime-scope-control.js +468 -0
  611. package/dist/services/runtime-scope-resume.js +605 -0
  612. package/dist/services/runtime-scope-stop.js +211 -0
  613. package/dist/services/runtime-scope-worker.js +314 -0
  614. package/dist/services/runtime-service.js +19 -14
  615. package/dist/services/schema-validation.js +10 -8
  616. package/dist/services/scope-writer-cleanup.js +27 -0
  617. package/dist/services/sessions.js +37 -91
  618. package/dist/services/setup.js +427 -0
  619. package/dist/services/stage-blocker.js +17 -7
  620. package/dist/services/stage-context.js +240 -18
  621. package/dist/services/stage-handlers.js +141 -0
  622. package/dist/services/stage-lifecycle.js +156 -119
  623. package/dist/services/stage-pause.js +222 -94
  624. package/dist/services/stage-report-renderer.js +230 -6
  625. package/dist/services/stage-work-graph.js +52 -0
  626. package/dist/services/technical-notes.js +31 -0
  627. package/dist/services/tooling.js +111 -44
  628. package/dist/services/usage.js +49 -101
  629. package/dist/services/verification-matrix.js +393 -0
  630. package/dist/services/version-status.js +1 -1
  631. package/dist/services/vnext-code-review.js +302 -91
  632. package/dist/services/vnext-code.js +325 -251
  633. package/dist/services/vnext-contracts.js +10 -1
  634. package/dist/services/vnext-execution-profile.js +80 -5
  635. package/dist/services/vnext-fanout.js +399 -20
  636. package/dist/services/vnext-merge.js +336 -114
  637. package/dist/services/vnext-plan-review.js +288 -133
  638. package/dist/services/vnext-plan.js +230 -106
  639. package/dist/services/vnext-protocolize.js +534 -96
  640. package/dist/services/vnext-specify.js +131 -84
  641. package/dist/services/vnext-workspace-policy.js +7 -2
  642. package/dist/services/work-registry.js +1950 -215
  643. package/dist/services/work-retry-context.js +55 -0
  644. package/dist/services/workspace-bootstrap.js +53 -15
  645. package/dist/services/workspace-files.js +85 -0
  646. package/dist/services/worktrees.js +108 -48
  647. package/dist/shared/entity-references.js +1 -0
  648. package/dist/shared/errors.js +27 -0
  649. package/dist/storage/agent-output.js +26 -0
  650. package/dist/storage/data-preservation.js +65 -0
  651. package/dist/storage/database.js +931 -40
  652. package/dist/storage/foreign-key-transaction.js +39 -0
  653. package/dist/storage/immutable-input.js +45 -0
  654. package/dist/storage/import-guard.js +159 -0
  655. package/dist/storage/memory-upgrade-schema-bootstrap.js +38 -0
  656. package/dist/storage/native-cleanup.js +52 -0
  657. package/dist/storage/paired-writer-migration.js +424 -0
  658. package/dist/storage/paths.js +17 -4
  659. package/dist/storage/projection-lock.js +73 -0
  660. package/dist/storage/work-references.js +23 -0
  661. package/dist/storage/writer-contract.js +96 -0
  662. package/dist/storage/writer-migration.js +346 -0
  663. package/dist/storage/writer-restore.js +217 -0
  664. package/dist/verification-components.json +384 -0
  665. package/package.json +52 -13
  666. package/tools/create-canon-release.mjs +33 -0
  667. package/tools/probe-codex-history.mjs +37 -0
  668. package/tools/produce-hybrid-release.mjs +41 -0
  669. package/tools/repair-paused-run-status.mjs +84 -0
  670. package/tools/verification-jobs.mjs +342 -0
@@ -0,0 +1,195 @@
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, validateHybridShape } from "./hybrid-contracts.js";
8
+ import { readBoundedReleaseFile } from "./release-source.js";
9
+ import { isCanonicalOnlyMemoryPath } from "./memory-layer.js";
10
+ import { localEnvironmentAllowed } from "./workspace-files.js";
11
+ import { admitBundledFlow } from "./stage-handlers.js";
12
+ import { normalizeFlowContract } from "../domain/flow-contract.js";
13
+ const limit = 1024 * 1024, manifestPath = "project-pack/manifest.json";
14
+ const hash = (bytes) => createHash("sha256").update(bytes).digest("hex");
15
+ function refuse(reason) {
16
+ throw new AppError("project_flow_source_invalid", "Project-local flow requires its own valid curated pack; use the supported pack upgrade/repair route", 2, { reason, phase: "prepare", effect: "no_effect", next_action: "inspect_project_pack_and_upgrade_or_repair" });
17
+ }
18
+ function safe(name) {
19
+ return typeof name === "string" && /^[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)*$/.test(name)
20
+ && name.split("/").every(part => ![".", "..", ".git", "node_modules", ".dd-flow"].includes(part.toLowerCase()) && localEnvironmentAllowed(part));
21
+ }
22
+ function schema(name) { return JSON.parse(fs.readFileSync(new URL(`../schemas/${name}.schema.json`, import.meta.url), "utf8")); }
23
+ function decoded(bytes) { try {
24
+ return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
25
+ }
26
+ catch {
27
+ return refuse("invalid_pack_json");
28
+ } }
29
+ function validate(scope, blobs) {
30
+ if (!scope || Object.keys(scope).sort().join() !== "flowId,projectRoot,workspace" || scope.flowId !== "interactive"
31
+ || [scope.projectRoot, scope.workspace].some(value => typeof value !== "string" || !path.isAbsolute(value)))
32
+ refuse("invalid_project_scope");
33
+ const manifest = decoded(blobs.get(manifestPath) ?? Buffer.alloc(0));
34
+ if (!new Ajv({ strict: false, validateFormats: false }).compile(schema("project-flow-pack-manifest"))(manifest)
35
+ || manifest.schema_id !== "dd-flow/project-flow-pack-manifest@2" || !/^[a-f0-9]{40}$/.test(manifest.source_commit)
36
+ || !semver.valid(manifest.canon_version_at_source_commit))
37
+ refuse("invalid_or_legacy_project_manifest");
38
+ if (manifest.included_files.length > 20_000 || manifest.included_files.some(name => !safe(name) || name === manifestPath
39
+ || name.startsWith("project-pack/") || isCanonicalOnlyMemoryPath(`dd-flow/${name}`)))
40
+ refuse("invalid_curated_inventory");
41
+ const names = [manifestPath, ...manifest.included_files], folded = new Set();
42
+ let total = 0;
43
+ if (blobs.size !== names.length)
44
+ refuse("pack_inventory_changed");
45
+ for (const name of names) {
46
+ if (folded.has(name.toLowerCase()))
47
+ refuse("aliased_pack_path");
48
+ folded.add(name.toLowerCase());
49
+ const bytes = blobs.get(name);
50
+ if (!bytes?.length || bytes.length > limit || (total += bytes.length) > 32 * limit)
51
+ refuse("missing_or_unbounded_pack_file");
52
+ if (name !== manifestPath && manifest.file_hashes?.[name] !== undefined && manifest.file_hashes[name] !== hash(bytes))
53
+ refuse("project_pack_file_changed");
54
+ }
55
+ const descriptorPath = `${scope.flowId}/flow-descriptor.json`, descriptor = decoded(blobs.get(descriptorPath) ?? Buffer.alloc(0));
56
+ if (validateHybridShape("flow-descriptor", descriptor).length || descriptor.id !== scope.flowId || descriptor.origin !== "project")
57
+ refuse("project_descriptor_required");
58
+ for (const stage of descriptor.stages)
59
+ for (const kind of ["instruction", "result_schema"]) {
60
+ const ref = stage[kind], bytes = blobs.get(ref.path);
61
+ if (!bytes || ref.path === manifestPath || !manifest.included_files.includes(ref.path) || hash(bytes) !== ref.sha256)
62
+ refuse("stage_source_not_in_project_pack");
63
+ try {
64
+ new TextDecoder("utf-8", { fatal: true }).decode(bytes);
65
+ }
66
+ catch {
67
+ refuse("invalid_stage_source_encoding");
68
+ }
69
+ if (kind === "result_schema")
70
+ decoded(bytes);
71
+ }
72
+ const compatibility = decoded(blobs.get("compatibility.json") ?? Buffer.alloc(0));
73
+ if (!new Ajv({ strict: false, validateFormats: false }).compile(schema("compatibility"))(compatibility))
74
+ refuse("invalid_project_compatibility");
75
+ const contract = normalizeFlowContract(decoded(blobs.get("flow-contract.json") ?? Buffer.alloc(0)));
76
+ if (contract.id !== manifest.flow_contract || compatibility.dd_flow_cli.flow_contract !== contract.id
77
+ || compatibility.memory_bank_version !== manifest.canon_version_at_source_commit)
78
+ refuse("project_contract_mismatch");
79
+ return { manifest, descriptorPath, compatibility };
80
+ }
81
+ /** Project pack data, not engine/handler admission. Manifest canon paths are
82
+ * provenance hints only: never follow them or fall back to global instructions. */
83
+ export class PreparedProjectFlowSource {
84
+ sha256;
85
+ #scope;
86
+ #blobs;
87
+ #facts;
88
+ #fresh;
89
+ constructor(scope, blobs, fresh) {
90
+ this.#facts = validate(scope, blobs);
91
+ this.#scope = structuredClone(scope);
92
+ this.#blobs = new Map([...blobs].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([name, bytes]) => [name, Buffer.from(bytes)]));
93
+ this.sha256 = hybridDigest({ scope, inventory: [...this.#blobs].map(([name, bytes]) => ({ path: name, sha256: hash(bytes) })) });
94
+ this.#fresh = fresh;
95
+ Object.freeze(this);
96
+ }
97
+ static fromProject(scope) {
98
+ try {
99
+ for (const root of [scope.projectRoot, scope.workspace])
100
+ if (fs.realpathSync(root) !== root || !fs.lstatSync(root).isDirectory())
101
+ refuse("noncanonical_project_root");
102
+ let root = scope.workspace;
103
+ for (const name of [".memory-bank", "dd-flow"]) {
104
+ root = path.join(root, name);
105
+ if (!fs.lstatSync(root).isDirectory())
106
+ refuse("linked_project_pack");
107
+ }
108
+ const read = (logical) => {
109
+ if (!safe(logical))
110
+ refuse("unsafe_pack_path");
111
+ let parent = root;
112
+ for (const part of logical.split("/").slice(0, -1)) {
113
+ parent = path.join(parent, part);
114
+ if (!fs.lstatSync(parent).isDirectory())
115
+ refuse("linked_project_pack");
116
+ }
117
+ return readBoundedReleaseFile(path.join(root, logical), limit);
118
+ };
119
+ const raw = read("manifest.json"), manifest = decoded(raw);
120
+ if (!new Ajv({ strict: false, validateFormats: false }).compile(schema("project-flow-pack-manifest"))(manifest)
121
+ || manifest.schema_id !== "dd-flow/project-flow-pack-manifest@2")
122
+ refuse("invalid_or_legacy_project_manifest");
123
+ const blobs = new Map([[manifestPath, raw]]);
124
+ if (manifest.included_files.length > 20_000)
125
+ refuse("unbounded_project_pack");
126
+ let total = raw.length;
127
+ for (const name of manifest.included_files) {
128
+ if (!safe(name) || isCanonicalOnlyMemoryPath(`dd-flow/${name}`) || name.startsWith("project-pack/"))
129
+ refuse("invalid_curated_inventory");
130
+ const bytes = read(name);
131
+ total += bytes.length;
132
+ if (total > 32 * limit)
133
+ refuse("unbounded_project_pack");
134
+ blobs.set(name, bytes);
135
+ }
136
+ if (!read("manifest.json").equals(raw))
137
+ refuse("manifest_changed_during_capture");
138
+ return new PreparedProjectFlowSource(scope, blobs, true);
139
+ }
140
+ catch (error) {
141
+ if (error instanceof AppError && error.code === "project_flow_source_invalid")
142
+ throw error;
143
+ return refuse("project_pack_unavailable_or_changed");
144
+ }
145
+ }
146
+ snapshot() { return { schema_id: "dd-flow/project-flow-source@1", scope: structuredClone(this.#scope), blobs: [...this.#blobs].map(([name, bytes]) => ({ path: name, base64: bytes.toString("base64") })) }; }
147
+ /** Data restoration only. expectedSha256 must come from independent request/
148
+ * RUN custody. Engine/handler admission is separate and never inferred here. */
149
+ static restoreRetained(value, expectedSha256) {
150
+ if (!value || Object.keys(value).sort().join() !== "blobs,schema_id,scope" || value.schema_id !== "dd-flow/project-flow-source@1"
151
+ || !Array.isArray(value.blobs) || value.blobs.length > 20_001)
152
+ refuse("invalid_retained_project_source");
153
+ const blobs = new Map();
154
+ let total = 0;
155
+ for (const item of value.blobs) {
156
+ if (!item || Object.keys(item).sort().join() !== "base64,path" || !safe(item.path) || typeof item.base64 !== "string" || item.base64.length > 2 * limit || blobs.has(item.path))
157
+ refuse("invalid_retained_project_source");
158
+ const bytes = Buffer.from(item.base64, "base64");
159
+ total += bytes.length;
160
+ if (!bytes.length || bytes.length > limit || total > 32 * limit || bytes.toString("base64") !== item.base64)
161
+ refuse("invalid_retained_project_source");
162
+ blobs.set(item.path, bytes);
163
+ }
164
+ const result = new PreparedProjectFlowSource(value.scope, blobs, false);
165
+ if (result.sha256 !== expectedSha256)
166
+ refuse("retained_project_source_changed");
167
+ return result;
168
+ }
169
+ blobs() { return new Map([...this.#blobs].map(([name, bytes]) => [name, Buffer.from(bytes)])); }
170
+ scope() { return structuredClone(this.#scope); }
171
+ descriptorReference() { const name = this.#facts.descriptorPath; return { path: name, sha256: hash(this.#blobs.get(name)) }; }
172
+ projectPackProvenance() { return { sha256: hybridDigest([...this.#blobs].map(([name, bytes]) => ({ path: name === manifestPath ? "dd-flow/manifest.json" : `dd-flow/${name}`, sha256: hash(bytes) })).sort((a, b) => a.path.localeCompare(b.path, "en"))), source_commit: this.#facts.manifest.source_commit }; }
173
+ canonSource() { return { version: this.#facts.manifest.canon_version_at_source_commit, commit: this.#facts.manifest.source_commit }; }
174
+ /** Declared project base, not a claim that customized instructions are bytes
175
+ * from an installed canonical archive. Actual data identity is the pack hash. */
176
+ canonProvenance() { return { ...this.canonSource(), archive_sha256: null }; }
177
+ resolveRegisteredFlow() { const ref = this.descriptorReference(); return admitBundledFlow(this.#blobs.get(ref.path), ref.sha256, this.#blobs); }
178
+ assertEngineCompatibility(engine) {
179
+ const value = this.#facts.compatibility;
180
+ if (engine.package_name !== value.engine.package_name || engine.package_name !== value.dd_flow_cli.package_name
181
+ || !semver.valid(engine.package_version) || !semver.valid(engine.engine_version)
182
+ || !semver.validRange(value.engine.version_range) || !semver.valid(value.dd_flow_cli.min_version)
183
+ || !semver.satisfies(engine.engine_version, value.engine.version_range, { includePrerelease: true })
184
+ || !semver.gte(engine.package_version, value.dd_flow_cli.min_version))
185
+ refuse("project_pack_engine_incompatible");
186
+ }
187
+ revalidate() {
188
+ if (!this.#fresh) {
189
+ validate(this.#scope, this.#blobs);
190
+ return;
191
+ }
192
+ if (PreparedProjectFlowSource.fromProject(this.#scope).sha256 !== this.sha256)
193
+ refuse("project_source_changed_before_retention");
194
+ }
195
+ }
@@ -0,0 +1,92 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { spawnSync } from "node:child_process";
4
+ import { createHash } from "node:crypto";
5
+ import { AppError } from "../shared/errors.js";
6
+ import { hybridDigest } from "./hybrid-contracts.js";
7
+ import { interactiveWorkPathAllowed } from "./interactive-work-batch.js";
8
+ import { ObservedMemorySources } from "./memory-source-observations.js";
9
+ import { memorySourceKey } from "./memory-stage-results.js";
10
+ import { assertMemoryGitRemovalSources } from "./memory-git-integration.js";
11
+ function refuse(reason) {
12
+ throw new AppError("project_git_integration_invalid", "Reviewed project files lack exact local Git integration", 2, { reason, effect: "no_effect" });
13
+ }
14
+ export function assertReviewedProjectGitInventory(references, removals) {
15
+ const valid = (ref) => ref?.root === "workspace" && interactiveWorkPathAllowed(ref.path)
16
+ && /^[a-f0-9]{64}$/.test(ref.sha256) && (Object.keys(ref).sort().join() === "path,root,sha256"
17
+ || Object.keys(ref).sort().join() === "git_mode,path,root,sha256" && ["100644", "100755"].includes(ref.git_mode));
18
+ if (!Array.isArray(references) || !Array.isArray(removals) || !references.length && !removals.length
19
+ || references.length + removals.length > 4096 || [...references, ...removals].some(ref => !valid(ref))
20
+ || new Set([...references, ...removals].map(ref => ref.path)).size !== references.length + removals.length)
21
+ refuse("invalid_reviewed_project_inventory");
22
+ }
23
+ /** Physical selected-file readback only, not review, policy or commit authority.
24
+ * Unrelated dirty files/index entries are deliberately neither committed nor
25
+ * treated as failures. The terminal owner must admit the original dirty input. */
26
+ export function observeReviewedProjectGitIntegration(input, environment, references, removals = []) {
27
+ assertReviewedProjectGitInventory(references, removals);
28
+ for (const root of [input.projectRoot, input.workspaceRoot]) {
29
+ if (!path.isAbsolute(root) || fs.realpathSync(root) !== root || !fs.lstatSync(root).isDirectory())
30
+ refuse("canonical_repository_root_required");
31
+ }
32
+ if (!path.isAbsolute(input.gitExecutable) || typeof input.integrationBranch !== "string" || !input.integrationBranch)
33
+ refuse("explicit_git_selection_required");
34
+ const env = { ...Object.fromEntries(Object.entries(environment).filter(([key]) => !key.startsWith("GIT_"))), GIT_OPTIONAL_LOCKS: "0", GIT_LITERAL_PATHSPECS: "1" };
35
+ const git = (root, args) => {
36
+ const result = spawnSync(input.gitExecutable, ["-c", "core.fsmonitor=false", "-C", root, ...args], { env, timeout: 10000, maxBuffer: 16 * 1024 * 1024, shell: false, windowsHide: true });
37
+ if (result.error || result.signal || result.status !== 0)
38
+ refuse("git_readback_failed");
39
+ return result.stdout;
40
+ };
41
+ const text = (root, args) => git(root, args).toString("utf8").trim();
42
+ const source = input.workspaceRoot, target = input.projectRoot, integrationRef = `refs/heads/${input.integrationBranch}`;
43
+ git(target, ["check-ref-format", integrationRef]);
44
+ const common = (root) => fs.realpathSync(path.resolve(root, text(root, ["rev-parse", "--git-common-dir"])));
45
+ const repository = common(source);
46
+ if (common(target) !== repository || [source, target].some(root => text(root, ["rev-parse", "--show-toplevel"]) !== root))
47
+ refuse("foreign_repository");
48
+ const workspaceBranch = text(source, ["symbolic-ref", "--short", "HEAD"]);
49
+ if (text(target, ["symbolic-ref", "--short", "HEAD"]) !== input.integrationBranch)
50
+ refuse("integration_branch_changed");
51
+ const head = text(source, ["rev-parse", "--verify", "HEAD^{commit}"]), integrated = text(target, ["rev-parse", "--verify", `${integrationRef}^{commit}`]);
52
+ git(target, ["merge-base", "--is-ancestor", head, integrated]);
53
+ const paths = [...references, ...removals].map(ref => ref.path);
54
+ const observations = [...new Set([source, target])].map(root => {
55
+ const visibility = git(root, ["ls-files", "-v", "-z", "--", ...paths]).toString("utf8");
56
+ if (visibility.split("\0").filter(Boolean).some(entry => !entry.startsWith("H ")))
57
+ refuse("selected_index_visibility_override");
58
+ git(root, ["diff", "--cached", "--exit-code", "--", ...paths]);
59
+ assertMemoryGitRemovalSources(root, removals);
60
+ const observed = ObservedMemorySources.capture({ workspace: root }, references.map(({ root, path }) => ({ root, path })));
61
+ const hashes = observed.hashes();
62
+ for (const ref of references) {
63
+ if (hashes.get(memorySourceKey("workspace", ref.path)) !== ref.sha256)
64
+ refuse("reviewed_workspace_bytes_changed");
65
+ if (process.platform !== "win32" && ((fs.lstatSync(path.join(root, ref.path)).mode & 0o111) !== 0) !== (ref.git_mode === "100755"))
66
+ refuse("reviewed_workspace_mode_changed");
67
+ }
68
+ return observed;
69
+ });
70
+ // ponytail: at most 4096 selected paths; batch Git reads if real interactive
71
+ // inventories make per-file subprocess latency material.
72
+ for (const [root, revision] of [[source, head], [target, integrated]]) {
73
+ for (const ref of references) {
74
+ const entry = git(root, ["ls-tree", "-z", revision, "--", ref.path]).toString("utf8");
75
+ if (!entry.startsWith(`${ref.git_mode ?? "100644"} blob `) || !entry.endsWith(`\t${ref.path}\0`))
76
+ refuse("reviewed_regular_git_blob_required");
77
+ if (createHash("sha256").update(git(root, ["cat-file", "blob", `${revision}:${ref.path}`])).digest("hex") !== ref.sha256)
78
+ refuse("reviewed_git_bytes_changed");
79
+ }
80
+ for (const ref of removals)
81
+ if (git(root, ["ls-tree", "-z", revision, "--", ref.path]).length)
82
+ refuse("removed_file_still_committed");
83
+ }
84
+ for (const observation of observations)
85
+ observation.revalidate();
86
+ if (text(source, ["rev-parse", "HEAD"]) !== head || text(target, ["rev-parse", integrationRef]) !== integrated)
87
+ refuse("integration_changed_during_observation");
88
+ return { schema_id: "dd-flow/project-git-integration-observation@1", project_root: target, workspace_root: source,
89
+ repository, workspace_branch: workspaceBranch, integration_ref: integrationRef, workspace_head: head, integration_head: integrated,
90
+ reviewed_files_sha256: hybridDigest([...references].sort((a, b) => a.path.localeCompare(b.path, "en"))),
91
+ removed_files_sha256: hybridDigest([...removals].sort((a, b) => a.path.localeCompare(b.path, "en"))) };
92
+ }
@@ -0,0 +1,97 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { AppError } from "../shared/errors.js";
4
+ import { projectRuntimeRoot, resolveProjectRoot } from "../storage/paths.js";
5
+ import { formatFullId, parseFullEntityId, slugFromRoot } from "../domain/entity-ids.js";
6
+ import { appendAudit } from "./audit.js";
7
+ /** Resolve filesystem identity before entering a composite SQL writer. */
8
+ export class PreparedProjectRegistration {
9
+ #root;
10
+ constructor(root) { this.#root = root; Object.freeze(this); }
11
+ static prepare(input) {
12
+ return new PreparedProjectRegistration(resolveProjectRoot(input.root));
13
+ }
14
+ root() { return this.#root; }
15
+ }
16
+ export function registerProject(context, input) {
17
+ return registerPreparedProject(context, PreparedProjectRegistration.prepare(input));
18
+ }
19
+ /** Metadata-only registration; the composite caller owns its SQL transaction. */
20
+ export function registerPreparedProject(context, prepared) {
21
+ if (!(prepared instanceof PreparedProjectRegistration))
22
+ throw new AppError("validation", "Project registration must be prepared", 2);
23
+ const root = prepared.root();
24
+ const existing = context.db.get("SELECT * FROM projects WHERE root = ?", [root]);
25
+ const now = context.now();
26
+ const project = existing ?? newProjectRecord(context, root, now);
27
+ if (existing) {
28
+ context.db.run("UPDATE projects SET status = 'active', updated_at = ? WHERE id = ?", [now, existing.id]);
29
+ }
30
+ else {
31
+ context.db.run("INSERT INTO projects (id, short_id, slug, root, status, state_root, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", [
32
+ project.id,
33
+ project.short_id,
34
+ project.slug,
35
+ project.root,
36
+ project.status,
37
+ project.state_root,
38
+ project.created_at,
39
+ project.updated_at
40
+ ]);
41
+ appendAudit(context, {
42
+ projectId: project.id,
43
+ eventType: "project.registered",
44
+ payload: { project_id: project.id, root }
45
+ });
46
+ }
47
+ return { ok: true, project: { ...project, status: "active", updated_at: now }, db_path: context.db.path };
48
+ }
49
+ export function normalizeStoredRoot(root) {
50
+ const absolute = path.resolve(root);
51
+ if (fs.existsSync(absolute)) {
52
+ return fs.realpathSync(absolute);
53
+ }
54
+ const parent = path.dirname(absolute);
55
+ if (fs.existsSync(parent)) {
56
+ return path.join(fs.realpathSync(parent), path.basename(absolute));
57
+ }
58
+ return absolute;
59
+ }
60
+ export function findProjectByRoot(context, root) {
61
+ return context.db.get("SELECT * FROM projects WHERE root = ?", [root]);
62
+ }
63
+ export function requireProjectByRoot(context, root) {
64
+ // Callers may receive a path through a native adapter or shell. Resolve
65
+ // aliases such as macOS `/var` -> `/private/var` before comparing with the
66
+ // canonical root persisted in the project registry.
67
+ const canonical = normalizeStoredRoot(root);
68
+ const project = findProjectByRoot(context, canonical);
69
+ if (!project) {
70
+ throw new AppError("not_found", `Project is not registered: ${canonical}`, 1);
71
+ }
72
+ return project;
73
+ }
74
+ export function newProjectRecord(context, root, now) {
75
+ const slug = slugFromRoot(root);
76
+ const id = nextFullProjectId(context, slug);
77
+ const { shortId } = parseFullEntityId(id);
78
+ return {
79
+ id,
80
+ short_id: shortId,
81
+ slug,
82
+ root,
83
+ status: "active",
84
+ state_root: projectRuntimeRoot(context.ddFlowHome, id),
85
+ created_at: now,
86
+ updated_at: now
87
+ };
88
+ }
89
+ export function nextFullProjectId(context, slug) {
90
+ const rows = context.db.all("SELECT id FROM projects WHERE id LIKE 'PRJ-%'");
91
+ const used = rows
92
+ .map((row) => /^PRJ-(\d{3})-/.exec(row.id)?.[1])
93
+ .filter((value) => Boolean(value))
94
+ .map((value) => Number(value));
95
+ const next = Math.max(0, ...used) + 1;
96
+ return formatFullId("PRJ", next, slug);
97
+ }
@@ -5,7 +5,7 @@ import { ensureDir } from "../storage/paths.js";
5
5
  import { getCliVersionReport } from "./build-info.js";
6
6
  import { projectDashboardHtmlPath, projectSummaryJsonPath } from "./config.js";
7
7
  import { queueForProject } from "./merge-queue.js";
8
- import { activeFlowSessionsForProject } from "./sessions.js";
8
+ import { activeFlowSessionsForProject } from "./hook-session-observation.js";
9
9
  import { getProjectVersionStatus } from "./version-status.js";
10
10
  export function projectSummaryPath(context, projectId) {
11
11
  return projectSummaryJsonPath(context, projectId);
@@ -1,44 +1,24 @@
1
- import fs from "node:fs";
2
1
  import path from "node:path";
3
- import { formatFullId, isFullEntityId, isShortEntityId, parseFullEntityId, slugFromRoot } from "../domain/entity-ids.js";
2
+ import { foreignKeyTransaction } from "../storage/foreign-key-transaction.js";
3
+ import { isFullEntityId, isShortEntityId, parseFullEntityId } from "../domain/entity-ids.js";
4
4
  import { AppError } from "../shared/errors.js";
5
5
  import { projectRuntimeRoot, resolveProjectRoot } from "../storage/paths.js";
6
6
  import { appendAudit } from "./audit.js";
7
+ import { registerProject, registerPreparedProject, PreparedProjectRegistration, normalizeStoredRoot, findProjectByRoot, requireProjectByRoot, newProjectRecord } from "./project-registry.js";
8
+ export { registerProject, registerPreparedProject, PreparedProjectRegistration, findProjectByRoot, requireProjectByRoot };
7
9
  import { activeCodexSessionBindingsForProject, activeFlowSessionBindingsForProject, codexHomeProfilesForProject, codexHookEventsForProject, hookStatusForProject } from "./hooks.js";
8
10
  import { dashboardMarkdownPath, globalDashboardMarkdownPath, readProjectConfig } from "./config.js";
9
11
  import { loadProjectFlowContract } from "../domain/flow-contract.js";
10
12
  import { buildStaticFlowGuidance } from "./flow-guidance.js";
11
13
  import { normalizeProtocolLifecycle } from "./protocol-lifecycle.js";
12
14
  import { buildProjectSummary, projectRegistrySummary, readPublishedProjectSummary } from "./project-summary.js";
13
- export function registerProject(context, input) {
14
- const root = resolveProjectRoot(input.root);
15
- const existing = findProjectByRoot(context, root);
16
- const now = context.now();
17
- const project = existing ?? newProjectRecord(context, root, now);
18
- if (existing) {
19
- context.db.run("UPDATE projects SET status = 'active', updated_at = ? WHERE id = ?", [now, existing.id]);
20
- }
21
- else {
22
- context.db.run("INSERT INTO projects (id, short_id, slug, root, status, state_root, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", [
23
- project.id,
24
- project.short_id,
25
- project.slug,
26
- project.root,
27
- project.status,
28
- project.state_root,
29
- project.created_at,
30
- project.updated_at
31
- ]);
32
- appendAudit(context, {
33
- projectId: project.id,
34
- eventType: "project.registered",
35
- payload: { project_id: project.id, root }
36
- });
37
- }
38
- return { ok: true, project: { ...project, status: "active", updated_at: now }, db_path: context.db.path };
39
- }
40
- export function archiveProject(context, input) {
41
- const reason = input.reason.trim();
15
+ export function prepareProjectArchive(context, input) {
16
+ if (Boolean(input.idOrAlias) === Boolean(input.root))
17
+ throw new AppError("usage", "Project archive requires exactly one project ID/alias or --root", 2);
18
+ for (const value of [input.idOrAlias, input.root])
19
+ if (value !== undefined && (typeof value !== "string" || !value.trim()))
20
+ throw new AppError("validation", "Project archive target must be a non-empty string", 2);
21
+ const reason = typeof input.reason === "string" ? input.reason.trim() : "";
42
22
  if (!reason) {
43
23
  throw new AppError("validation", "project archive requires --reason", 2);
44
24
  }
@@ -50,6 +30,10 @@ export function archiveProject(context, input) {
50
30
  if (!project) {
51
31
  throw new AppError("not_found", "Project is not registered.", 1, { root: input.root, input: input.idOrAlias });
52
32
  }
33
+ return { project, reason };
34
+ }
35
+ export function archiveProject(context, input) {
36
+ const { project, reason } = prepareProjectArchive(context, input);
53
37
  const now = context.now();
54
38
  const result = context.db.run("UPDATE projects SET status = 'archived', updated_at = ? WHERE id = ? AND status <> 'archived'", [now, project.id]);
55
39
  if (result.changes === 1) {
@@ -67,17 +51,6 @@ export function archiveProject(context, input) {
67
51
  ...(result.changes === 1 ? {} : { skipped: true, reason: "already_archived" })
68
52
  };
69
53
  }
70
- function normalizeStoredRoot(root) {
71
- const absolute = path.resolve(root);
72
- if (fs.existsSync(absolute)) {
73
- return fs.realpathSync(absolute);
74
- }
75
- const parent = path.dirname(absolute);
76
- if (fs.existsSync(parent)) {
77
- return path.join(fs.realpathSync(parent), path.basename(absolute));
78
- }
79
- return absolute;
80
- }
81
54
  export function resolveProject(context, input) {
82
55
  const candidates = resolveProjectCandidates(context, input.idOrAlias);
83
56
  if (candidates.length === 1) {
@@ -139,9 +112,7 @@ export function migrateProjectIds(context, input) {
139
112
  if (conflictingProject) {
140
113
  throw new AppError("conflict", `Target project id already exists: ${target.id}`, 1, plan);
141
114
  }
142
- context.db.exec("PRAGMA foreign_keys = OFF");
143
- context.db.exec("BEGIN IMMEDIATE");
144
- try {
115
+ foreignKeyTransaction(context.db, () => {
145
116
  context.db.run("UPDATE projects SET id = ?, short_id = ?, slug = ?, state_root = ?, updated_at = ? WHERE id = ?", [target.id, target.short_id, target.slug, target.state_root, now, oldId]);
146
117
  for (const table of projectReferenceTables()) {
147
118
  context.db.run(`UPDATE ${table} SET project_id = ? WHERE project_id = ?`, [target.id, oldId]);
@@ -153,14 +124,7 @@ export function migrateProjectIds(context, input) {
153
124
  foreign_key_errors: foreignKeyErrors
154
125
  });
155
126
  }
156
- context.db.exec("COMMIT");
157
- context.db.exec("PRAGMA foreign_keys = ON");
158
- }
159
- catch (error) {
160
- context.db.exec("ROLLBACK");
161
- context.db.exec("PRAGMA foreign_keys = ON");
162
- throw error;
163
- }
127
+ });
164
128
  appendAudit(context, {
165
129
  projectId: target.id,
166
130
  eventType: "project.id_migrated",
@@ -228,31 +192,6 @@ export function getProjectStatus(context, input) {
228
192
  }
229
193
  };
230
194
  }
231
- export function findProjectByRoot(context, root) {
232
- return context.db.get("SELECT * FROM projects WHERE root = ?", [root]);
233
- }
234
- export function requireProjectByRoot(context, root) {
235
- const project = findProjectByRoot(context, root);
236
- if (!project) {
237
- throw new AppError("not_found", `Project is not registered: ${root}`, 1);
238
- }
239
- return project;
240
- }
241
- function newProjectRecord(context, root, now) {
242
- const slug = slugFromRoot(root);
243
- const id = nextFullProjectId(context, slug);
244
- const { shortId } = parseFullEntityId(id);
245
- return {
246
- id,
247
- short_id: shortId,
248
- slug,
249
- root,
250
- status: "active",
251
- state_root: projectRuntimeRoot(context.ddFlowHome, id),
252
- created_at: now,
253
- updated_at: now
254
- };
255
- }
256
195
  function backfilledTypedProjectRecord(context, project, typed, now) {
257
196
  return {
258
197
  ...project,
@@ -262,15 +201,6 @@ function backfilledTypedProjectRecord(context, project, typed, now) {
262
201
  updated_at: now
263
202
  };
264
203
  }
265
- function nextFullProjectId(context, slug) {
266
- const rows = context.db.all("SELECT id FROM projects WHERE id LIKE 'PRJ-%'");
267
- const used = rows
268
- .map((row) => /^PRJ-(\d{3})-/.exec(row.id)?.[1])
269
- .filter((value) => Boolean(value))
270
- .map((value) => Number(value));
271
- const next = Math.max(0, ...used) + 1;
272
- return formatFullId("PRJ", next, slug);
273
- }
274
204
  function typedProjectMetadata(project) {
275
205
  if (!isFullEntityId(project.id)) {
276
206
  return null;
@@ -0,0 +1,71 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { AppError } from "../shared/errors.js";
5
+ import { publishImmutableInput } from "../storage/immutable-input.js";
6
+ const digest = (text) => crypto.createHash("sha256").update(text).digest("hex");
7
+ /** Describe the exact delivery before the existing operation receipt is settled.
8
+ * This does not issue commands or replace the original semantic prompt. */
9
+ export function preparePromptDelivery(value) {
10
+ if (!value || typeof value !== "object" || Array.isArray(value))
11
+ return value;
12
+ const packet = value, text = packet.worker_prompt_markdown;
13
+ if (typeof text !== "string" || typeof packet.prompt_path !== "string")
14
+ return value;
15
+ if (!path.isAbsolute(packet.prompt_path))
16
+ throw new AppError("prompt_delivery_invalid", "Prompt delivery requires an absolute original prompt path", 1, { effect: "committed" });
17
+ const sha256 = digest(text);
18
+ let file = path.join(path.dirname(packet.prompt_path), "prompt-deliveries", `${sha256}.md`);
19
+ try {
20
+ if (fs.lstatSync(packet.prompt_path).isFile() && !fs.lstatSync(packet.prompt_path).isSymbolicLink()
21
+ && fs.readFileSync(packet.prompt_path, "utf8") === text)
22
+ file = packet.prompt_path;
23
+ }
24
+ catch { /* A retained delivery can republish an absent original without replay. */ }
25
+ const retained = packet.prompt_delivery;
26
+ if (retained && (retained.sha256 !== sha256 || retained.path !== file)) {
27
+ // An original file may disappear after commit. Keep the exact retained locator.
28
+ if (retained.sha256 !== sha256 || !path.isAbsolute(retained.path)
29
+ || retained.path !== packet.prompt_path && retained.path !== path.join(path.dirname(packet.prompt_path), "prompt-deliveries", `${sha256}.md`)) {
30
+ throw new AppError("prompt_delivery_invalid", "Retained delivery differs from its committed bytes", 1, { effect: "committed" });
31
+ }
32
+ file = retained.path;
33
+ }
34
+ const delivery = { path: file, sha256 };
35
+ // Keep the locator visible even when native tools clip verbose JSON metadata.
36
+ return Object.assign({ prompt_delivery: delivery }, packet, { prompt_delivery: delivery });
37
+ }
38
+ /** Publish only retained bytes, after commit and before advertising the locator. */
39
+ export function publishPromptDelivery(value) {
40
+ if (!value || typeof value !== "object")
41
+ return;
42
+ const packet = value, delivery = packet.prompt_delivery;
43
+ if (!delivery)
44
+ return;
45
+ const text = packet.worker_prompt_markdown;
46
+ try {
47
+ if (typeof text !== "string" || digest(text) !== delivery.sha256 || !path.isAbsolute(delivery.path))
48
+ throw new Error("Delivery checksum mismatch");
49
+ if (typeof packet.prompt_path !== "string" || !path.isAbsolute(packet.prompt_path))
50
+ throw new Error("Delivery has no original prompt directory");
51
+ // Revalidate retained routing before touching the filesystem. System path
52
+ // aliases (/var on macOS) are allowed; a delivery-directory symlink is not.
53
+ preparePromptDelivery(packet);
54
+ const directory = path.dirname(delivery.path);
55
+ if (delivery.path !== packet.prompt_path) {
56
+ const stat = fs.lstatSync(directory, { throwIfNoEntry: false });
57
+ if (stat && (!stat.isDirectory() || stat.isSymbolicLink()))
58
+ throw new Error("Delivery directory is not an owned regular directory");
59
+ }
60
+ fs.mkdirSync(path.dirname(delivery.path), { recursive: true, mode: 0o700 });
61
+ if (delivery.path !== packet.prompt_path
62
+ && fs.realpathSync(directory) !== path.join(fs.realpathSync(path.dirname(packet.prompt_path)), "prompt-deliveries"))
63
+ throw new Error("Delivery directory escaped its original prompt directory");
64
+ publishImmutableInput(delivery.path, Buffer.from(text), "prompt_delivery_conflict");
65
+ fs.accessSync(delivery.path, fs.constants.R_OK);
66
+ }
67
+ catch (cause) {
68
+ throw new AppError("prompt_delivery_pending", "Operation committed; reconcile its retained delivery before continuing. Do not repeat the lifecycle operation or execute the old prompt", 1, { effect: "committed", publication_pending: true, path: delivery.path, sha256: delivery.sha256, cause: cause instanceof Error ? cause.message : String(cause) });
69
+ }
70
+ }
71
+ export const promptDeliveryInstruction = "Read the complete plain Markdown file at prompt_delivery.path; it is the exact current instruction packet (SHA-256 in prompt_delivery.sha256). Read all chunks if needed. The JSON response is routing metadata, not the primary prompt. If prompt_delivery is absent on a legacy response, read the complete worker_prompt_markdown from response_file. If publication is pending, stop and reconcile the existing operation; never replay Stage/Work start or use an old prompt.";