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

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 (227) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/build-info.json +8 -8
  3. package/dist/cli/command-inputs.js +33 -3
  4. package/dist/cli/command-metadata.js +73 -2
  5. package/dist/cli/delivery.js +108 -0
  6. package/dist/cli/diagnostic-invocation.js +23 -7
  7. package/dist/cli/diagnostic.js +14 -3
  8. package/dist/cli/help.js +117 -1
  9. package/dist/cli/hook-ingress.js +36 -49
  10. package/dist/cli/interactive-invocation.js +33 -0
  11. package/dist/cli/interactive.js +114 -0
  12. package/dist/cli/memory-fix-invocation.js +52 -0
  13. package/dist/cli/memory-fix.js +100 -0
  14. package/dist/cli/memory-flow-admission.js +7 -3
  15. package/dist/cli/memory-init.js +5 -4
  16. package/dist/cli/native-hook-ingress.js +5 -1
  17. package/dist/cli/native-hook-preparation.js +31 -4
  18. package/dist/cli/run-cli.js +273 -19
  19. package/dist/cli.js +17 -3
  20. package/dist/domain/delivery-flows.js +8 -0
  21. package/dist/domain/distill-flow.js +20 -0
  22. package/dist/domain/interactive-flow.js +1 -0
  23. package/dist/domain/memory-fix-flow.js +2 -0
  24. package/dist/domain/review-fix-flow.js +2 -0
  25. package/dist/domain/source-snapshot-flows.js +4 -0
  26. package/dist/harness-runtime/bin/dd-agy.mjs +18 -3
  27. package/dist/harness-runtime/bin/dd-grok.mjs +15 -5
  28. package/dist/harness-runtime/bin/dd-zcode.mjs +15 -7
  29. package/dist/harness-runtime/lib/agy-error-boundary.mjs +18 -10
  30. package/dist/harness-runtime/lib/agy-native-inspection.mjs +12 -3
  31. package/dist/harness-runtime/lib/agy-native-inventory.mjs +19 -0
  32. package/dist/harness-runtime/lib/agy-terminal-envelope.mjs +13 -6
  33. package/dist/harness-runtime/lib/agy-transcript-stream.mjs +54 -0
  34. package/dist/harness-runtime/lib/daemon-observation.d.mts +1 -0
  35. package/dist/harness-runtime/lib/daemon-observation.mjs +12 -4
  36. package/dist/harness-runtime/lib/daemon-operations.mjs +20 -5
  37. package/dist/harness-runtime/lib/dd-agy-daemon.d.mts +1 -0
  38. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +371 -114
  39. package/dist/harness-runtime/lib/dd-codex-daemon.mjs +43 -3
  40. package/dist/harness-runtime/lib/dd-codex.mjs +36 -4
  41. package/dist/harness-runtime/lib/dd-droid-daemon.mjs +25 -11
  42. package/dist/harness-runtime/lib/dd-droid.mjs +124 -11
  43. package/dist/harness-runtime/lib/dd-grok-daemon.d.mts +1 -0
  44. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +137 -25
  45. package/dist/harness-runtime/lib/dd-grok.mjs +4 -2
  46. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +170 -25
  47. package/dist/harness-runtime/lib/dd-opencode.mjs +40 -19
  48. package/dist/harness-runtime/lib/dd-zcode-daemon.d.mts +1 -0
  49. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +115 -22
  50. package/dist/harness-runtime/lib/dd-zcode.mjs +75 -36
  51. package/dist/harness-runtime/lib/delegation-instructions.d.mts +1 -0
  52. package/dist/harness-runtime/lib/delegation-instructions.mjs +10 -3
  53. package/dist/harness-runtime/lib/delivery-command.mjs +84 -0
  54. package/dist/harness-runtime/lib/driver-recovery.mjs +0 -19
  55. package/dist/harness-runtime/lib/droid-observation.mjs +9 -5
  56. package/dist/harness-runtime/lib/lifecycle-contract.d.mts +1 -0
  57. package/dist/harness-runtime/lib/lifecycle-contract.mjs +2 -1
  58. package/dist/harness-runtime/lib/native-hook-command.d.mts +3 -2
  59. package/dist/harness-runtime/lib/native-hook-command.mjs +63 -8
  60. package/dist/harness-runtime/lib/native-streams.mjs +3 -10
  61. package/dist/harness-runtime/lib/opencode-plugin.mjs +36 -9
  62. package/dist/harness-runtime/lib/operation-errors.mjs +13 -0
  63. package/dist/harness-runtime/lib/operation-progress.mjs +6 -2
  64. package/dist/harness-runtime/lib/process-json.mjs +4 -5
  65. package/dist/harness-runtime/lib/tool-observations.mjs +20 -10
  66. package/dist/harness-runtime/lib/zcode-native-hook-ownership.mjs +109 -0
  67. package/dist/schemas/code-work-result.schema.json +2 -1
  68. package/dist/schemas/delivery-stage-result.schema.json +286 -0
  69. package/dist/schemas/distill-stage-result.schema.json +667 -0
  70. package/dist/schemas/distill-work-result.schema.json +428 -0
  71. package/dist/schemas/execution-bundle.schema.json +6 -2
  72. package/dist/schemas/interactive-stage-result.schema.json +47 -0
  73. package/dist/schemas/interactive-work-result.schema.json +63 -0
  74. package/dist/schemas/mb-fix-stage-result.schema.json +93 -0
  75. package/dist/schemas/project-flow-pack-manifest.schema.json +2 -2
  76. package/dist/schemas/review-fix-stage-result.schema.json +210 -0
  77. package/dist/schemas/run-control-receipt.schema.json +1 -0
  78. package/dist/services/assigned-lifecycle.js +382 -0
  79. package/dist/services/check-runner-evidence.js +77 -10
  80. package/dist/services/check-runner-proof.js +69 -1
  81. package/dist/services/cli-operation-classifier.js +6 -1
  82. package/dist/services/code-checks.js +56 -23
  83. package/dist/services/codex-hook-delivery.js +11 -2
  84. package/dist/services/controller-execution.js +4 -1
  85. package/dist/services/controller-fanout.js +9 -4
  86. package/dist/services/controller-memory-worker.js +6 -4
  87. package/dist/services/controller-result-authority.js +122 -0
  88. package/dist/services/dashboard.js +4 -2
  89. package/dist/services/delivery-access.js +123 -0
  90. package/dist/services/delivery-approval.js +68 -0
  91. package/dist/services/delivery-artifact.js +86 -0
  92. package/dist/services/delivery-checks.js +178 -0
  93. package/dist/services/delivery-execution.js +181 -0
  94. package/dist/services/delivery-intents.js +212 -0
  95. package/dist/services/delivery-operation.js +81 -0
  96. package/dist/services/delivery-policy.js +91 -0
  97. package/dist/services/delivery-procedures.js +43 -0
  98. package/dist/services/delivery-request.js +99 -0
  99. package/dist/services/delivery-result.js +144 -0
  100. package/dist/services/delivery-stage-commands.js +26 -0
  101. package/dist/services/delivery-stage-entry.js +56 -0
  102. package/dist/services/delivery-stage-handlers.js +135 -0
  103. package/dist/services/delivery-stage-results.js +94 -0
  104. package/dist/services/descriptor-coordinator-session.js +3 -1
  105. package/dist/services/descriptor-run-start.js +24 -4
  106. package/dist/services/descriptor-stage-coordinator.js +78 -10
  107. package/dist/services/descriptor-stage-settlement.js +59 -14
  108. package/dist/services/diagnostic-repair-intake.js +123 -0
  109. package/dist/services/diagnostic-repair-source-intake.js +102 -0
  110. package/dist/services/diagnostic-report.js +30 -0
  111. package/dist/services/diagnostic-run-bundle.js +48 -9
  112. package/dist/services/diagnostic-snapshot.js +2 -2
  113. package/dist/services/diagnostic-stage-handlers.js +3 -2
  114. package/dist/services/diagnostic-stage-results.js +26 -0
  115. package/dist/services/diagnostic-start.js +56 -6
  116. package/dist/services/diagnostic-work-collection.js +3 -3
  117. package/dist/services/distill-document-publication.js +280 -0
  118. package/dist/services/distill-promotion.js +197 -0
  119. package/dist/services/distill-publication-custody.js +162 -0
  120. package/dist/services/distill-stage-handlers.js +249 -0
  121. package/dist/services/distill-stage-results.js +105 -0
  122. package/dist/services/distill-user-inputs.js +4 -0
  123. package/dist/services/distill-work-batch.js +42 -0
  124. package/dist/services/distill-work-collection.js +74 -0
  125. package/dist/services/distill-work-registration.js +93 -0
  126. package/dist/services/distill-work-results.js +98 -0
  127. package/dist/services/eval-snapshots.js +17 -7
  128. package/dist/services/external-work-launch.js +8 -2
  129. package/dist/services/flow-catalog.js +24 -0
  130. package/dist/services/frozen-engine.js +19 -2
  131. package/dist/services/generic-execution.js +4 -3
  132. package/dist/services/harness-adapter.js +2 -14
  133. package/dist/services/hook-memory-routing.js +1 -1
  134. package/dist/services/hooks.js +31 -6
  135. package/dist/services/hybrid-contracts.js +6 -1
  136. package/dist/services/installed-flow-source.js +37 -2
  137. package/dist/services/interactive-attached-session.js +215 -0
  138. package/dist/services/interactive-baseline-custody.js +54 -0
  139. package/dist/services/interactive-before-versions.js +148 -0
  140. package/dist/services/interactive-bundle-data.js +85 -0
  141. package/dist/services/interactive-checks.js +179 -0
  142. package/dist/services/interactive-execution.js +33 -0
  143. package/dist/services/interactive-finish-integration.js +236 -0
  144. package/dist/services/interactive-git-baseline.js +230 -0
  145. package/dist/services/interactive-git-dispatch.js +278 -0
  146. package/dist/services/interactive-input-delivery.js +82 -0
  147. package/dist/services/interactive-mutation-scope.js +231 -0
  148. package/dist/services/interactive-request.js +287 -0
  149. package/dist/services/interactive-run-bundle.js +109 -0
  150. package/dist/services/interactive-stage-entry.js +41 -0
  151. package/dist/services/interactive-stage-handlers.js +289 -0
  152. package/dist/services/interactive-stage-observation.js +136 -0
  153. package/dist/services/interactive-stage-results.js +111 -0
  154. package/dist/services/interactive-user-inputs.js +142 -0
  155. package/dist/services/interactive-work-batch.js +43 -0
  156. package/dist/services/interactive-work-collection.js +119 -0
  157. package/dist/services/interactive-work-completion.js +180 -0
  158. package/dist/services/interactive-work-context.js +249 -0
  159. package/dist/services/interactive-work-history.js +112 -0
  160. package/dist/services/interactive-work-registration.js +124 -0
  161. package/dist/services/interactive-work-results.js +115 -0
  162. package/dist/services/interactive-work-start.js +155 -0
  163. package/dist/services/lifecycle-invocations.js +214 -24
  164. package/dist/services/managed-daemon-binding.js +52 -1
  165. package/dist/services/memory-compose-handler.js +2 -22
  166. package/dist/services/memory-finish-integration.js +58 -17
  167. package/dist/services/memory-fix-finish-integration.js +129 -0
  168. package/dist/services/memory-fix-git-dispatch.js +139 -0
  169. package/dist/services/memory-fix-intake-custody.js +11 -0
  170. package/dist/services/memory-fix-intake-settlement.js +127 -0
  171. package/dist/services/memory-fix-publication.js +196 -0
  172. package/dist/services/memory-fix-repair-admission.js +116 -0
  173. package/dist/services/memory-fix-request.js +141 -0
  174. package/dist/services/memory-fix-run-bundle.js +83 -0
  175. package/dist/services/memory-fix-scope.js +78 -0
  176. package/dist/services/memory-fix-sources.js +85 -0
  177. package/dist/services/memory-fix-stage-entry.js +24 -0
  178. package/dist/services/memory-fix-stage-handlers.js +282 -0
  179. package/dist/services/memory-fix-stage-results.js +106 -0
  180. package/dist/services/memory-fix-workspace.js +127 -0
  181. package/dist/services/memory-flow-user-inputs.js +88 -0
  182. package/dist/services/memory-init-contexts.js +55 -5
  183. package/dist/services/memory-init-controller-start.js +20 -4
  184. package/dist/services/memory-layer.js +7 -3
  185. package/dist/services/memory-native-review-copy.js +27 -3
  186. package/dist/services/memory-repair-document-delta.js +1 -0
  187. package/dist/services/project-flow-source.js +195 -0
  188. package/dist/services/project-git-integration.js +92 -0
  189. package/dist/services/repair-intents.js +2 -4
  190. package/dist/services/retained-native-hook.js +245 -0
  191. package/dist/services/review-fix-handoff.js +82 -0
  192. package/dist/services/review-fix-intake-custody.js +17 -0
  193. package/dist/services/review-fix-stage-entry.js +43 -0
  194. package/dist/services/review-fix-stage-handlers.js +176 -0
  195. package/dist/services/review-fix-stage-results.js +86 -0
  196. package/dist/services/run-control-worker.js +42 -1
  197. package/dist/services/run-control.js +40 -5
  198. package/dist/services/run-controller-adapter.js +37 -3
  199. package/dist/services/run-controller-process.js +12 -4
  200. package/dist/services/run-controller-recovery.js +46 -6
  201. package/dist/services/run-controller-state.js +3 -2
  202. package/dist/services/run-controller.js +209 -43
  203. package/dist/services/run-recovery.js +31 -2
  204. package/dist/services/run-timeline.js +59 -0
  205. package/dist/services/runs.js +18 -31
  206. package/dist/services/sessions.js +2 -1
  207. package/dist/services/stage-handlers.js +55 -3
  208. package/dist/services/stage-lifecycle.js +4 -3
  209. package/dist/services/stage-pause.js +26 -9
  210. package/dist/services/stage-report-renderer.js +2 -6
  211. package/dist/services/technical-notes.js +31 -0
  212. package/dist/services/verification-matrix.js +1 -1
  213. package/dist/services/version-status.js +1 -1
  214. package/dist/services/vnext-code-review.js +74 -5
  215. package/dist/services/vnext-code.js +9 -32
  216. package/dist/services/vnext-fanout.js +53 -8
  217. package/dist/services/vnext-merge.js +10 -5
  218. package/dist/services/vnext-plan-review.js +1 -1
  219. package/dist/services/vnext-plan.js +1 -1
  220. package/dist/services/vnext-protocolize.js +1 -1
  221. package/dist/services/vnext-specify.js +10 -5
  222. package/dist/services/work-registry.js +252 -66
  223. package/dist/services/worktrees.js +7 -4
  224. package/dist/storage/database.js +2 -1
  225. package/dist/verification-components.json +82 -0
  226. package/package.json +4 -3
  227. package/tools/verification-jobs.mjs +342 -0
@@ -13,7 +13,8 @@ import { PreparedMemoryInitLintCapability } from "../services/memory-init-lint-c
13
13
  import { PreparedMemoryInitWorktrunkCapability } from "../services/memory-init-worktrunk-capability.js";
14
14
  import { produceMemoryInitNativeCapacity } from "../services/memory-init-native-capacity.js";
15
15
  import { openMemoryInitStores, assertMemoryInitStorePrerequisites } from "../services/memory-init-stores.js";
16
- import { prepareMemoryInitControllerStart, prepareMemoryUpgradeControllerStart } from "../services/memory-init-controller-start.js";
16
+ import { prepareMemoryInitControllerStart, prepareMemoryUpgradeControllerStart, prepareInteractiveControllerStart, prepareDeliveryControllerStart } from "../services/memory-init-controller-start.js";
17
+ import { isDeliveryFlow } from "../domain/delivery-flows.js";
17
18
  import { runControllerStatus } from "../services/run-controller.js";
18
19
  import { requireRun } from "../services/run-controller-state.js";
19
20
  import { requireProjectByRoot } from "../services/projects.js";
@@ -28,8 +29,8 @@ import { onboardExecutor } from "../services/executor-onboarding.js";
28
29
  import { readOperatorProfiles, readOperatorProfileInput } from "../services/operator-profiles.js";
29
30
  import { resolveDdFlowHome } from "../storage/paths.js";
30
31
  import { askExecutorChoice } from "./executor-onboarding.js";
31
- import { isDiagnosticFlow } from "../domain/diagnostic-flows.js";
32
- import { prepareDiagnosticControllerStart } from "../services/memory-init-controller-start.js";
32
+ import { isSourceSnapshotFlow } from "../domain/source-snapshot-flows.js";
33
+ import { prepareDiagnosticControllerStart, prepareMemoryFixControllerStart } from "../services/memory-init-controller-start.js";
33
34
  /** Backpressure bounds the observing client's output; closing it never controls the RUN. */
34
35
  export async function writeMemoryInitObservation(stdout, text) {
35
36
  const disconnected = () => Boolean(stdout.destroyed);
@@ -186,7 +187,7 @@ export async function launchAndObserveMemoryFlow(context, invocation, started, f
186
187
  await writeMemoryInitObservation(io.stdout, `${JSON.stringify(writeResponseFile(response, output), null, output.json || output.progressJsonl ? undefined : 2)}\n`);
187
188
  return 0;
188
189
  }
189
- const launch = isDiagnosticFlow(flowId) ? prepareDiagnosticControllerStart(context, invocation.scope, flowId)
190
+ const launch = isDeliveryFlow(flowId) ? prepareDeliveryControllerStart(context, invocation.scope, flowId) : flowId === "interactive" ? prepareInteractiveControllerStart(context, invocation.scope) : flowId === "mb-fix" ? prepareMemoryFixControllerStart(context, invocation.scope) : isSourceSnapshotFlow(flowId) ? prepareDiagnosticControllerStart(context, invocation.scope, flowId)
190
191
  : (flowId === "mb-init" ? prepareMemoryInitControllerStart : prepareMemoryUpgradeControllerStart)(context, invocation.scope);
191
192
  // Use the existing RUN-bound router: a global CLI must not launch its own
192
193
  // controller code in place of the independently frozen RUN executable.
@@ -1,7 +1,7 @@
1
1
  import { AppError, errorRecord } from "../shared/errors.js";
2
2
  import { parseCommandArgs } from "../services/lifecycle-command.js";
3
3
  import { channel } from "node:diagnostics_channel";
4
- import { nativeHookNonParticipation } from "./native-hook-preparation.js";
4
+ import { nativeHookAssignedSettlement, nativeHookNonParticipation } from "./native-hook-preparation.js";
5
5
  /** These ingress commands consume a prepared store; they never prepare it. */
6
6
  export function isNativeHookIngress(args) {
7
7
  return args[2] === "handle" && ((args[1] === "event" && ["agy", "grok", "droid", "opencode", "zcode"].includes(args[0] ?? ""))
@@ -31,6 +31,10 @@ export async function dispatchNativeHook(args, stdin, env) {
31
31
  phase("ack");
32
32
  return unrelated;
33
33
  }
34
+ if (nativeHookAssignedSettlement(args, stdin, env)) {
35
+ phase("ack");
36
+ return { ok: true, observed: false, reason: "cli_invocation_owns_admission" };
37
+ }
34
38
  const [hooks, { createContext }, { resolveDdFlowHome }] = await Promise.all([
35
39
  import("../services/hooks.js"), import("../runtime/context.js"), import("../storage/paths.js")
36
40
  ]);
@@ -1,12 +1,12 @@
1
1
  import path from "node:path";
2
2
  import { parseJsonObject } from "../shared/json.js";
3
- import { continuationCommand, parseLifecycleCommand } from "../services/lifecycle-command.js";
3
+ import { commandOption, continuationCommand, parseLifecycleCommand } from "../services/lifecycle-command.js";
4
4
  const object = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
5
5
  const text = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
6
6
  /** Only a validated, ordinary before-tool command can skip the stateful handler.
7
7
  * In particular after-tool, Stop, malformed and ambiguous events remain owned
8
8
  * by their existing handler; this gate does not invent an admission policy. */
9
- export function nativeHookNonParticipation(args, stdin) {
9
+ function beforeCommand(args, stdin) {
10
10
  const payload = parseJsonObject(stdin || "{}", "native hook stdin");
11
11
  let command;
12
12
  if (args[0] === "zcode" && args[1] === "event") {
@@ -47,9 +47,36 @@ export function nativeHookNonParticipation(args, stdin) {
47
47
  const input = object(payload.input);
48
48
  command = text(input.command) ?? text(input.cmd) ?? text(input.CommandLine);
49
49
  }
50
- if (!command)
50
+ return command ? { command, reason: args[0] === "zcode" && args[1] === "event" ? "acp_evidence_only" : "event_not_participating" } : null;
51
+ }
52
+ export function nativeHookNonParticipation(args, stdin) {
53
+ const before = beforeCommand(args, stdin);
54
+ if (!before)
51
55
  return null;
56
+ const { command, reason } = before;
52
57
  const parsed = parseLifecycleCommand(command);
53
58
  return parsed.participation === "none" && !continuationCommand(command)
54
- ? { ok: true, observed: false, reason: args[0] === "zcode" && args[1] === "event" ? "acp_evidence_only" : "event_not_participating" } : null;
59
+ ? { ok: true, observed: false, reason } : null;
60
+ }
61
+ /** A supplied ID is not a grant. The executing CLI must prove its retained
62
+ * assignment; the synchronous native hook has no second admission role. */
63
+ export function assignedLifecycleHookCommand(command, env) {
64
+ if (!env.DD_FLOW_DAEMON_ID)
65
+ return false;
66
+ const parsed = parseLifecycleCommand(command);
67
+ return parsed.kind === "standalone" && Boolean(commandOption(parsed.invocation, "invocation-id"))
68
+ && ["stage_start", "stage_finish", "stage_pause", "stage_resume", "work_finish", "work_fail"].includes(parsed.invocation.operation);
69
+ }
70
+ /** The native daemon has already retained this exact delivery; the CLI will
71
+ * verify and materialize it before admitting the issued Work invocation. */
72
+ export function retainedWorkStartHookCommand(command, binding) {
73
+ const retained = object(binding), parsed = parseLifecycleCommand(command);
74
+ return parsed.kind === "standalone" && parsed.invocation.operation === "work_start"
75
+ && Boolean(commandOption(parsed.invocation, "invocation-id"))
76
+ && retained.schema_id === "dd-flow/hook-request@1" && retained.source_harness === "codex-desktop"
77
+ && retained.native_command === command && typeof retained.request_id === "string" && retained.request_id.length > 0;
78
+ }
79
+ export function nativeHookAssignedSettlement(args, stdin, env) {
80
+ const before = beforeCommand(args, stdin);
81
+ return Boolean(before && assignedLifecycleHookCommand(before.command, env));
55
82
  }
@@ -3,13 +3,14 @@ import { prepareResponseDestination, writeResponseFile } from "./response-file.j
3
3
  import { preparePromptDelivery, publishPromptDelivery } from "../services/prompt-delivery.js";
4
4
  import { requiredOption, optionalOption, optionalNumber, optionalPositiveNumber } from "./argument-values.js";
5
5
  import { resolveCommandPaths, resolveCommandProjectRoot } from "../services/command-context.js";
6
- import { assertAuxiliaryCommandScope, cliManagedInvocationScope, manualRecoveryInvocationScope, assertManualRecoveryInvocationTarget } from "../services/lifecycle-invocations.js";
6
+ import { assertAuxiliaryCommandScope, cliManagedInvocationScope, manualRecoveryInvocationScope, assertManualRecoveryInvocationTarget, currentAssignedLifecycle } from "../services/lifecycle-invocations.js";
7
7
  import path from "node:path";
8
8
  import { randomUUID } from "node:crypto";
9
9
  import { quote } from "shell-quote";
10
10
  import { observeLifecycleCommand, observedLifecycleNativeEvent } from "../services/lifecycle-invocations.js";
11
11
  import { verifyCodexHookDelivery } from "../services/codex-hook-delivery.js";
12
12
  import { assertLifecycleInvocationCurrent, awaitLifecycleInvocation, bindLifecyclePublishedPacket, expandLifecycleInvocationArgs, issueLifecycleInvocation, prepareLifecycleIssuance, lifecycleInvocationScope, observedLifecycleDiagnostic, observedLifecycleInvocation, resolveObservedLifecycleArgs, retainObservedLifecycleSemantics, settleLifecycleInvocation, settleLifecyclePreparationRejection, settleLifecycleRejection, validateLifecyclePathAliases } from "../services/lifecycle-invocations.js";
13
+ import { readAcceptedAssignedWork } from "../services/assigned-lifecycle.js";
13
14
  import { createContext, createRouterContext } from "../runtime/context.js";
14
15
  import { dispatchNativeHook, isNativeHookIngress } from "./native-hook-ingress.js";
15
16
  import { isRuntimeMaintenance, runtimeMaintenanceDiagnostics, withMaintenanceDiagnosticScope } from "./runtime-maintenance-diagnostics.js";
@@ -66,9 +67,43 @@ import { applyVnextMerge, getVnextMergeRequest, isVnextMergeRun, prepareVnextMer
66
67
  import { sdlcStageHandlers } from "../services/stage-handlers.js";
67
68
  import { startMemoryStage, finishMemoryStage, startMemoryUpgradeStage, finishMemoryUpgradeStage } from "../services/memory-stage-dispatch.js";
68
69
  import { startDiagnosticStage, finishDiagnosticStage } from "../services/diagnostic-stage-handlers.js";
70
+ import { startDistillStage, finishDistillStage } from "../services/distill-stage-handlers.js";
71
+ import { startMemoryFixStage } from "../services/memory-fix-stage-entry.js";
72
+ import { finishMemoryFixStage } from "../services/memory-fix-stage-handlers.js";
73
+ import { startReviewFixStage } from "../services/review-fix-stage-entry.js";
74
+ import { finishReviewFixStage } from "../services/review-fix-stage-handlers.js";
75
+ import { startInteractiveStage } from "../services/interactive-stage-entry.js";
76
+ import { isDeliveryFlow } from "../domain/delivery-flows.js";
77
+ import { startDeliveryStage, readDeliveryStageScope, assertDeliveryCommandOwner } from "../services/delivery-stage-entry.js";
78
+ import { finishDeliveryStage } from "../services/delivery-stage-handlers.js";
79
+ import { prepareDeliveryChecks } from "../services/delivery-checks.js";
80
+ import { executeDeliveryOperation } from "../services/delivery-operation.js";
81
+ import { observeDeliveryResult } from "../services/delivery-result.js";
82
+ import { prepareDeliveryProjectBinding } from "../services/delivery-policy.js";
83
+ import { deliveryApprovalScope } from "../services/delivery-approval.js";
84
+ import { issueDeliveryStageCommands } from "../services/delivery-stage-commands.js";
85
+ import { readDescriptorStageInput } from "../services/descriptor-stage-coordinator.js";
86
+ import { readAcceptedStageData } from "../services/stage-report-renderer.js";
87
+ import { finishInteractiveStage, registerInteractiveReviewCorrection, registerInteractiveCorrectionReview } from "../services/interactive-stage-handlers.js";
88
+ import { observeInteractiveOriginalGitInputs } from "../services/interactive-finish-integration.js";
89
+ import { readInteractiveUserInputs } from "../services/interactive-user-inputs.js";
90
+ import { deliverInteractiveUserInput } from "../services/interactive-input-delivery.js";
91
+ import { PreparedInteractiveMutationScope } from "../services/interactive-mutation-scope.js";
92
+ import { PreparedInteractiveChecks } from "../services/interactive-checks.js";
93
+ import { registerInteractiveStageGraph } from "../services/interactive-work-registration.js";
94
+ import { readInteractiveWorkGit } from "../services/interactive-work-start.js";
95
+ import { integrateInteractiveFinish } from "../services/interactive-git-dispatch.js";
96
+ import { readMemoryFixSourceIntake } from "../services/memory-fix-intake-custody.js";
97
+ import { readMemoryFixUserInputs } from "../services/diagnostic-repair-intake.js";
98
+ import { prepareMemoryFixScopeEvidence } from "../services/memory-fix-scope.js";
99
+ import { prepareMemoryFixPublication } from "../services/memory-fix-publication.js";
100
+ import { integrateMemoryFixFinish } from "../services/memory-fix-git-dispatch.js";
69
101
  import { isDiagnosticFlow } from "../domain/diagnostic-flows.js";
70
102
  import { bindStageCoordinatorWork } from "../services/work-registry.js";
71
103
  import { registerMemoryCompositionFromStage, publishMemoryUpgradeFromStage } from "../services/memory-compose-handler.js";
104
+ import { publishDistillFromStage } from "../services/distill-promotion.js";
105
+ import { readDistillUserInputs } from "../services/distill-user-inputs.js";
106
+ import { hybridDigest } from "../services/hybrid-contracts.js";
72
107
  import { runMemoryVerificationChecks } from "../services/memory-verify-handler.js";
73
108
  import { registerMemoryReviewFromStage, collectMemoryInitialReviewFromStage } from "../services/memory-review-handler.js";
74
109
  import { PreparedRetainedMemoryReviewAuthority } from "../services/memory-retained-review-authority.js";
@@ -77,7 +112,7 @@ import { registerMemoryCorrectionsFromStage, registerMemorySecondCorrectionsFrom
77
112
  import { integrateMemoryFinishFromStage, registerMemoryFinishEvidenceFromStage } from "../services/memory-finish-handler.js";
78
113
  import { registerMemoryRepairBaselineFromStage, registerMemorySecondRepairBaselineFromStage, reserveMemoryRepairWriterCopyFromStage, reserveMemorySecondRepairCopyFromStage, materializeMemoryRepairWriterCopyFromStage, materializeMemorySecondRepairCopyFromStage, prepareMemoryRepairDispatchFromStage, prepareMemorySecondRepairDispatchFromStage, registerMemoryRepairCurrentViewFromStage, registerMemorySecondRepairCurrentViewFromStage, registerMemoryRepairPublicationSourceFromStage, reserveMemoryRepairPublicationAgainstSourceFromStage, reserveMemorySecondRepairPublicationFromStage, applyMemoryRepairPublicationFromStage, applyMemorySecondRepairPublicationFromStage, finishMemoryRepairPublicationFromStage, finishMemorySecondRepairPublicationFromStage } from "../services/memory-review-handler.js";
79
114
  import { mergeServerStatus, serveMergeRequests, stopMergeServer } from "../services/merge-server.js";
80
- import { getVnextFanoutStatus, memoryStageFanoutDescriptor, diagnosticStageFanoutDescriptor, observeVnextNativeChildren, prepareNativeObservations, reconcileVnextFanout } from "../services/vnext-fanout.js";
115
+ import { getVnextFanoutStatus, registeredStageFanoutDescriptor, observeVnextNativeChildren, prepareNativeObservations, reconcileVnextFanout } from "../services/vnext-fanout.js";
81
116
  import { pauseStageForUser, resumeStageAfterUser, prepareStagePause, prepareStageResume, stagePauseCommand } from "../services/stage-pause.js";
82
117
  import { runtimeCommand } from "../services/runtime-command.js";
83
118
  import { managedLifecycleCommand } from "../services/lifecycle-invocations.js";
@@ -132,6 +167,10 @@ async function runCliRequest(args, io, env) {
132
167
  let output;
133
168
  try {
134
169
  output = parseOutputOptions(args);
170
+ // Expand before routing/context selection, after stripping transport flags.
171
+ // The alias keeps the existing RUN's engine and prepared-store rules.
172
+ if (output.args[0] === "finish")
173
+ output.args = ["interactive", "finish", ...output.args.slice(1)];
135
174
  }
136
175
  catch (error) {
137
176
  const rejection = isAppError(error) ? error : new AppError("usage", error instanceof Error ? error.message : String(error), 2);
@@ -349,6 +388,7 @@ async function runCliRequest(args, io, env) {
349
388
  // after admission; retained outcomes must not need a fresh hook receipt.
350
389
  if (invocationId) {
351
390
  const command = quote(["dd-flow", ...invocationArgs]);
391
+ let nextNativeObservation = 0;
352
392
  const admission = await awaitLifecycleInvocation(dispatchContext, { id: invocationId, command,
353
393
  validateArgs: () => {
354
394
  try {
@@ -362,7 +402,14 @@ async function runCliRequest(args, io, env) {
362
402
  }
363
403
  },
364
404
  prepare: async () => { preparedInput = await prepareCliInput(invocationArgs, dispatchContext, io, scopeProjectRoot, output.responseFile, preparedRoute, commandProgress(io, output)); },
365
- assertCurrent: scope => assertLifecycleInvocationCurrent(dispatchContext, scope, command), progress: commandProgress(io, output) });
405
+ assertCurrent: scope => assertLifecycleInvocationCurrent(dispatchContext, scope, command), progress: commandProgress(io, output),
406
+ ...((env.DD_FLOW_RUNTIME_OWNER || env.DD_FLOW_CODEX_STATE_DIR || env.DD_AGY_STATE_DIR || env.DD_GROK_STATE_DIR || env.DD_ZCODE_STATE_DIR) ? { reconcileNativeObservation: async (scope, onProgress) => {
407
+ if (Date.now() < nextNativeObservation)
408
+ return;
409
+ nextNativeObservation = Date.now() + 250;
410
+ const { reconcileRetainedNativeHook } = await import("../services/retained-native-hook.js");
411
+ await reconcileRetainedNativeHook(dispatchContext, { scope, invocationId, onProgress });
412
+ } } : {}) });
366
413
  if (admission.replay) {
367
414
  retainedOutcome = admission.outcome;
368
415
  settleHook = undefined;
@@ -372,8 +419,10 @@ async function runCliRequest(args, io, env) {
372
419
  invocationSettlement = { context: dispatchContext, id: invocationId };
373
420
  if (observedInvocation)
374
421
  retainObservedLifecycleSemantics(dispatchContext, invocationId, invocationArgs);
375
- dispatchArgs = [...invocationArgs, "--hook-event-id", admission.eventKey];
376
- preparedInput?.route?.parsed.options.set("hook-event-id", [admission.eventKey]);
422
+ if (admission.kind === "native_hook") {
423
+ dispatchArgs = [...invocationArgs, "--hook-event-id", admission.eventKey];
424
+ preparedInput?.route?.parsed.options.set("hook-event-id", [admission.eventKey]);
425
+ }
377
426
  dispatchContext.env.DD_FLOW_INVOCATION_SCOPE = JSON.stringify(lifecycleInvocationScope(dispatchContext, invocationId));
378
427
  dispatchContext.env.DD_FLOW_CURRENT_INVOCATION = invocationId;
379
428
  }
@@ -498,6 +547,23 @@ async function runCliRequest(args, io, env) {
498
547
  io.stderr.write(`Invocation settlement persistence failed: ${String(persistenceError)}\n`);
499
548
  }
500
549
  }
550
+ if (invocationSettlement && error.details.work_result_accepted === true) {
551
+ const accepted = readAcceptedAssignedWork(invocationSettlement.context, invocationSettlement.id);
552
+ if (accepted) {
553
+ // The Work/WorkSession commit is authoritative. Report its retained
554
+ // answer even if a derivative publication failed after that commit.
555
+ const payload = addWarnings(accepted, [{ code: "work_post_commit_pending", message: "Work result accepted; derivative publication requires reconciliation" }]);
556
+ try {
557
+ writeResponseFile(payload, output);
558
+ }
559
+ catch { /* Accepted SQL reply remains available on stdout/replay. */ }
560
+ if (output.json)
561
+ writeJson(io.stdout, payload);
562
+ else
563
+ io.stdout.write(renderHumanResult(output.args, payload));
564
+ return completedCommandExitCode(payload);
565
+ }
566
+ }
501
567
  if (settleHook) {
502
568
  try {
503
569
  settleHook({ error: isAppError(error) ? error : { code: "unexpected", message: String(error), details: {} } });
@@ -560,6 +626,9 @@ function databaseModeForCommand(args, classification) {
560
626
  if (isRuntimeMaintenance(args))
561
627
  return "read_existing";
562
628
  const [family, command] = args;
629
+ // Bound interactive operations never initialize or migrate a RUN store.
630
+ if (family === "interactive" && classification.mode !== "read_only_diagnostics")
631
+ return "prepared_existing";
563
632
  if (family === "migration" && command === "readiness")
564
633
  return "prepared_existing";
565
634
  // Managed attempts are issued only from a prepared store. Opening that
@@ -872,6 +941,57 @@ async function prepareCliInput(...args) {
872
941
  async function prepareCliInputValue(args, context, io, scopeProjectRoot, responseFile = null, route = prepareCommandRoute(args), progress) {
873
942
  const { family, command, parsed } = route;
874
943
  const prepared = { route };
944
+ if (family === "delivery" && ["checks", "execute"].includes(command ?? "")) {
945
+ const file = requiredOption(parsed, "result-file"), text = prepareTextFile(file, "Delivery input", 1024 * 1024);
946
+ const value = prepareJsonText(text.text, { file, label: "Delivery input" }).value;
947
+ const keys = command === "checks" ? "path,sha256,subject_ref,version" : "basis,expires_at,reason,scope_sha256,user_inputs_sha256";
948
+ if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).sort().join() !== keys)
949
+ throw new AppError("usage", "Delivery input must match the selected command's exact JSON contract", 2, { phase: "prepare", effect: "no_effect" });
950
+ if (command === "checks")
951
+ prepared.deliveryArtifact = value;
952
+ else
953
+ prepared.deliveryApproval = value;
954
+ }
955
+ if (family === "interactive" && command === "integrate" && hasOption(parsed, "result-file")) {
956
+ const file = requiredOption(parsed, "result-file"), input = prepareTextFile(file, "Interactive Git agreement", 1024 * 1024);
957
+ const value = prepareJsonText(input.text, { file, label: "Interactive Git agreement" }).value;
958
+ if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).sort().join() !== "basis,include_existing_paths,reason")
959
+ throw new AppError("usage", "Interactive Git agreement requires basis, include_existing_paths and reason", 2, { phase: "prepare", effect: "no_effect" });
960
+ prepared.interactiveGitAgreement = value;
961
+ }
962
+ if (family === "interactive" && command === "checks") {
963
+ const file = requiredOption(parsed, "result-file"), input = prepareTextFile(file, "Interactive check selection", 1024 * 1024);
964
+ const value = prepareJsonText(input.text, { file, label: "Interactive check selection" }).value;
965
+ if (!value || typeof value !== "object" || Array.isArray(value)
966
+ || !["additionalChecks", "additionalChecks,noChecksReason"].includes(Object.keys(value).sort().join()))
967
+ throw new AppError("usage", "Interactive checks require additionalChecks and optional noChecksReason", 2, { phase: "prepare", effect: "no_effect" });
968
+ prepared.interactiveChecksProposal = value;
969
+ }
970
+ if (family === "interactive" && command === "scope") {
971
+ const file = requiredOption(parsed, "result-file"), input = prepareTextFile(file, "Interactive mutation scope", 1024 * 1024);
972
+ const value = prepareJsonText(input.text, { file, label: "Interactive mutation scope" }).value;
973
+ if (!value || typeof value !== "object" || Array.isArray(value)
974
+ || Object.keys(value).sort().join() !== "basis,expectedInputsSha256,paths,reason,requestId")
975
+ throw new AppError("usage", "Interactive scope requires requestId, paths, basis, reason and expectedInputsSha256", 2, { phase: "prepare", effect: "no_effect" });
976
+ const basis = recordObject(recordObject(value).basis);
977
+ if (!basis || Object.keys(basis).sort().join() !== "event_id,role,sha256"
978
+ || !["request", "turn", "answer", "finish"].includes(String(basis.role))
979
+ || typeof basis.event_id !== "number" || !Number.isSafeInteger(basis.event_id) || basis.event_id < 0
980
+ || typeof basis.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(basis.sha256))
981
+ throw new AppError("usage", "Interactive scope basis requires role request|turn|answer|finish, a nonnegative integer event_id and a SHA-256", 2, {
982
+ reason: "invalid_scope_basis_shape", phase: "prepare", effect: "no_effect", recoverable: true,
983
+ retry_command: runtimeCommand(context, ["interactive", "scope", "--project-root", requiredOption(parsed, "project-root"),
984
+ "--run", requiredOption(parsed, "run"), "--result-file", file, "--json", "--progress-jsonl"]),
985
+ retry_instruction: "Correct only the rejected basis shape. For the original request use role=request, event_id=0 and initial_request.sha256 from interactive inputs. For a later user message copy its exact role, integer event_id and sha256 from messages; a question is not user approval. No scope was retained by this call. Reuse this exact retry_command; valid-shaped but unowned evidence or conflicting accepted scope identities remain refusals."
986
+ });
987
+ prepared.interactiveScopeProposal = value;
988
+ }
989
+ if (family === "interactive" && (command === "turn" || command === "finish")) {
990
+ const input = prepareTextFile(requiredOption(parsed, "intake-file"), "Interactive user input", 1024 * 1024);
991
+ prepared.interactiveInputBytes = Buffer.from(input.text);
992
+ if (!prepared.interactiveInputBytes.length || !/^[a-f0-9]{64}$/.test(requiredOption(parsed, "expected-inputs-sha256")))
993
+ throw new AppError("usage", "Interactive delivery requires nonempty UTF-8 input and its current input digest", 2, { phase: "prepare", effect: "no_effect" });
994
+ }
875
995
  if (optionalOption(parsed, "reason-file")) {
876
996
  const value = prepareJsonFile(requiredOption(parsed, "reason-file"), "Check recovery evidence").value;
877
997
  if (!value || typeof value.reason !== "string" || !value.reason.trim() || Object.keys(value).some(key => key !== "reason"))
@@ -1232,7 +1352,7 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
1232
1352
  const bundle = readFlowRunExecutionBundle(context, { projectRoot: requiredOption(parsed, "project-root"), runId: requiredPosition(parsed, 0, "run-id") });
1233
1353
  if (bundle)
1234
1354
  prepared.stageBindingBundle = { stage, bundle, ...(contextSha256 ? { contextSha256 } : {}) };
1235
- if (bundle && (["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id) || isDiagnosticFlow(bundle.descriptor.descriptor.id))) {
1355
+ if (bundle && (["interactive", "mb-init", "mb-upgrade", "mb-distill", "mb-fix", "review-fix"].includes(bundle.descriptor.descriptor.id) || isDiagnosticFlow(bundle.descriptor.descriptor.id) || isDeliveryFlow(bundle.descriptor.descriptor.id))) {
1236
1356
  bundle.descriptor.stage(stage);
1237
1357
  if (hasOption(parsed, "dir"))
1238
1358
  throw new AppError("usage", "Memory stage layout belongs to its frozen descriptor", 2);
@@ -1240,7 +1360,7 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
1240
1360
  if (loaded)
1241
1361
  prepared.stageStart = { externalContext: loaded };
1242
1362
  prepared.memoryStage = { operation: "start", bytes: loaded ? Buffer.from(loaded.bytes) : Buffer.alloc(0),
1243
- flowId: isDiagnosticFlow(bundle.descriptor.descriptor.id) ? bundle.descriptor.descriptor.id : bundle.descriptor.descriptor.id === "mb-upgrade" ? "mb-upgrade" : "mb-init" };
1363
+ flowId: isDeliveryFlow(bundle.descriptor.descriptor.id) ? bundle.descriptor.descriptor.id : bundle.descriptor.descriptor.id === "interactive" ? "interactive" : bundle.descriptor.descriptor.id === "review-fix" ? "review-fix" : bundle.descriptor.descriptor.id === "mb-fix" ? "mb-fix" : bundle.descriptor.descriptor.id === "mb-distill" ? "mb-distill" : isDiagnosticFlow(bundle.descriptor.descriptor.id) ? bundle.descriptor.descriptor.id : bundle.descriptor.descriptor.id === "mb-upgrade" ? "mb-upgrade" : "mb-init" };
1244
1364
  return prepared;
1245
1365
  }
1246
1366
  }
@@ -1345,7 +1465,8 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
1345
1465
  prepared.observations = prepareNativeObservations(prepareJsonFile(requiredOption(parsed, "observations-file"), "native observations").value);
1346
1466
  }
1347
1467
  if (family === "memory" && (["compose", "corrections"].includes(command ?? "") && parsed.positional[0] === "register"
1348
- || command === "repair" && parsed.positional[0] === "publication-reserve")) {
1468
+ || command === "repair" && parsed.positional[0] === "publication-reserve"
1469
+ || command === "distill" && parsed.positional[0] === "publish")) {
1349
1470
  try {
1350
1471
  const bytes = prepareFileBytes(requiredOption(parsed, "result-file"), `Memory ${command} result`, 1024 * 1024).bytes;
1351
1472
  if (!bytes.length || bytes.length > 1024 * 1024)
@@ -1359,6 +1480,12 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
1359
1480
  throw error;
1360
1481
  }
1361
1482
  }
1483
+ if (family === "memory" && command === "fix" && ["scope", "publish", "integrate"].includes(parsed.positional[0] ?? "") && hasOption(parsed, "result-file")) {
1484
+ const file = requiredOption(parsed, "result-file"), input = prepareTextFile(file, "Memory repair proposal", 1024 * 1024);
1485
+ prepared.memoryFixProposal = prepareJsonText(input.text, { file, label: "Memory repair proposal" }).value;
1486
+ if (!prepared.memoryFixProposal || typeof prepared.memoryFixProposal !== "object" || Array.isArray(prepared.memoryFixProposal))
1487
+ throw new AppError("usage", "Memory repair proposal must be a JSON object", 2, { phase: "prepare", effect: "no_effect" });
1488
+ }
1362
1489
  if (family !== "stage" || command !== "finish")
1363
1490
  return prepared;
1364
1491
  const projectRoot = requiredOption(parsed, "project-root");
@@ -1375,9 +1502,9 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
1375
1502
  const resultFile = optionalOption(parsed, "result-file") ?? semanticFile;
1376
1503
  const runtime = run(projectRoot, runId);
1377
1504
  const retainedFlowId = JSON.parse(runtime.indexJson).execution_bundle?.flow_id;
1378
- if (["mb-init", "mb-upgrade"].includes(retainedFlowId) || isDiagnosticFlow(retainedFlowId)) {
1505
+ if (["interactive", "mb-init", "mb-upgrade", "mb-distill", "mb-fix", "review-fix"].includes(retainedFlowId) || isDiagnosticFlow(retainedFlowId) || isDeliveryFlow(retainedFlowId)) {
1379
1506
  const bundle = readFlowRunExecutionBundle(context, { projectRoot, runId });
1380
- if (!bundle || !["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id) && !isDiagnosticFlow(bundle.descriptor.descriptor.id))
1507
+ if (!bundle || !["interactive", "mb-init", "mb-upgrade", "mb-distill", "mb-fix", "review-fix"].includes(bundle.descriptor.descriptor.id) && !isDiagnosticFlow(bundle.descriptor.descriptor.id) && !isDeliveryFlow(bundle.descriptor.descriptor.id))
1381
1508
  throw new AppError("cli_input_unprepared", "Registered RUN bundle is unavailable", 1);
1382
1509
  bundle.descriptor.stage(stage);
1383
1510
  if (["dir", "outcome", "decision-file", "verification-file", "retry-check", "reason", "reason-file", "request", "work"].some(option => hasOption(parsed, option)))
@@ -1387,7 +1514,7 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
1387
1514
  const bytes = resultStdin ? Buffer.from(await readStdin(io.stdin, 1024 * 1024)) : prepareFileBytes(resultFile, "Memory stage result", 1024 * 1024).bytes;
1388
1515
  if (!bytes.length || bytes.length > 1024 * 1024)
1389
1516
  throw new AppError("usage", "Memory stage result exceeds its byte bound", 2);
1390
- prepared.memoryStage = { operation: "finish", bytes, flowId: isDiagnosticFlow(bundle.descriptor.descriptor.id) ? bundle.descriptor.descriptor.id : bundle.descriptor.descriptor.id === "mb-upgrade" ? "mb-upgrade" : "mb-init" };
1517
+ prepared.memoryStage = { operation: "finish", bytes, flowId: isDeliveryFlow(bundle.descriptor.descriptor.id) ? bundle.descriptor.descriptor.id : bundle.descriptor.descriptor.id === "interactive" ? "interactive" : bundle.descriptor.descriptor.id === "review-fix" ? "review-fix" : bundle.descriptor.descriptor.id === "mb-fix" ? "mb-fix" : bundle.descriptor.descriptor.id === "mb-distill" ? "mb-distill" : isDiagnosticFlow(bundle.descriptor.descriptor.id) ? bundle.descriptor.descriptor.id : bundle.descriptor.descriptor.id === "mb-upgrade" ? "mb-upgrade" : "mb-init" };
1391
1518
  return prepared;
1392
1519
  }
1393
1520
  const terminalReplay = (name) => {
@@ -1776,12 +1903,12 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
1776
1903
  const externalContext = prepared.stageStart?.externalContext;
1777
1904
  if (prepared.memoryStage?.operation === "start") {
1778
1905
  const runId = requiredPosition(parsed, 0, "run-id");
1779
- const event = hookEventId ?? findRecentMatchingHookEvent(context, {
1906
+ const event = hookEventId ?? (currentAssignedLifecycle(context) ? undefined : findRecentMatchingHookEvent(context, {
1780
1907
  projectId: requireProjectByRoot(context, resolveProjectRoot(projectRoot)).id,
1781
1908
  matchKey: entityReferenceVariants(runId).map(reference => stageStartMatchKey(reference, stage, projectRoot, contextSha256)),
1782
1909
  errorCode: "trusted_session_binding_required", operation: "Memory stage start"
1783
- }).eventKey;
1784
- const work = (isDiagnosticFlow(prepared.memoryStage.flowId) ? startDiagnosticStage : prepared.memoryStage.flowId === "mb-upgrade" ? startMemoryUpgradeStage : startMemoryStage)(context, { projectRoot, runId, stage, bytes: prepared.memoryStage.bytes });
1910
+ }).eventKey);
1911
+ const work = (isDeliveryFlow(prepared.memoryStage.flowId) ? startDeliveryStage : prepared.memoryStage.flowId === "interactive" ? startInteractiveStage : prepared.memoryStage.flowId === "review-fix" ? startReviewFixStage : prepared.memoryStage.flowId === "mb-fix" ? startMemoryFixStage : prepared.memoryStage.flowId === "mb-distill" ? startDistillStage : isDiagnosticFlow(prepared.memoryStage.flowId) ? startDiagnosticStage : prepared.memoryStage.flowId === "mb-upgrade" ? startMemoryUpgradeStage : startMemoryStage)(context, { projectRoot, runId, stage, bytes: prepared.memoryStage.bytes });
1785
1912
  try {
1786
1913
  const binding = bindStageCoordinatorWork(context, { workId: work.work_id, hookEventId: event, stage,
1787
1914
  promptPath: work.prompt_path, resultPath: work.result_path, ...(contextSha256 ? { contextSha256 } : {}) });
@@ -1791,9 +1918,12 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
1791
1918
  const finish = managedLifecycleCommand(context, runtimeCommand(context, ["stage", "finish", runId,
1792
1919
  "--stage", stage, "--project-root", projectRoot, "--result-file", work.result_path, "--json"]));
1793
1920
  const pause = stagePauseCommand(context, { projectRoot, runId, stage, workId: work.work_id });
1794
- const orchestration = memoryStageFanoutDescriptor(context, { projectRoot, runId, stage }) ?? diagnosticStageFanoutDescriptor(context, { projectRoot, runId, stage });
1921
+ // These assignments belong to this native coordinator delivery, not to
1922
+ // the immutable semantic packet restored by auxiliary owners.
1923
+ const deliveryInstructions = isDeliveryFlow(prepared.memoryStage.flowId) ? issueDeliveryStageCommands(context, { flowId: prepared.memoryStage.flowId, projectRoot, runId, stage, stageRoot: path.dirname(work.result_path) }).instructions : "";
1924
+ const orchestration = registeredStageFanoutDescriptor(context, { projectRoot, runId, stage });
1795
1925
  const delivery = { ...work, binding, ...(orchestration ? { orchestration } : {}), next: { finish_command: finish, pause_command: pause },
1796
- worker_prompt_markdown: `${work.worker_prompt_markdown}\n## Current lifecycle commands\n\nWrite the semantic result to the assigned result path, then execute exactly:\n${finish}\n\nFor a required user choice, write the question file named by this command, then execute exactly:\n${pause}\n` };
1926
+ worker_prompt_markdown: `${work.worker_prompt_markdown}${deliveryInstructions}\n## Current lifecycle commands\n\nWrite the semantic result to the assigned result path, then execute exactly:\n${finish}\n\nFor a required user choice, write the question file named by this command, then execute exactly:\n${pause}\n` };
1797
1927
  bindLifecyclePublishedPacket(context, delivery.worker_prompt_markdown);
1798
1928
  return controlLifecycleReply(context, { projectRoot, runId }, delivery);
1799
1929
  }
@@ -1803,6 +1933,8 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
1803
1933
  }
1804
1934
  }
1805
1935
  const claimVnextStageStart = (runId) => {
1936
+ if (currentAssignedLifecycle(context)?.operation === "stage_start")
1937
+ return undefined;
1806
1938
  registerProject(context, { root: projectRoot });
1807
1939
  return findRecentMatchingHookEvent(context, {
1808
1940
  projectId: requireProjectByRoot(context, resolveProjectRoot(projectRoot)).id,
@@ -1900,12 +2032,12 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
1900
2032
  // Descriptor settlement validates exact coordinator custody and claims
1901
2033
  // the fresh hook atomically with result acceptance. Do not consume it
1902
2034
  // through the SDLC lifecycle owner before that settlement.
1903
- return controlledReply((isDiagnosticFlow(prepared.memoryStage.flowId) ? finishDiagnosticStage : prepared.memoryStage.flowId === "mb-upgrade" ? finishMemoryUpgradeStage : finishMemoryStage)(context, { projectRoot, runId, stage, bytes: prepared.memoryStage.bytes,
1904
- hookEventId: hookEventId ?? findRecentMatchingHookEvent(context, {
2035
+ return controlledReply((isDeliveryFlow(prepared.memoryStage.flowId) ? finishDeliveryStage : prepared.memoryStage.flowId === "interactive" ? finishInteractiveStage : prepared.memoryStage.flowId === "review-fix" ? finishReviewFixStage : prepared.memoryStage.flowId === "mb-fix" ? finishMemoryFixStage : prepared.memoryStage.flowId === "mb-distill" ? finishDistillStage : isDiagnosticFlow(prepared.memoryStage.flowId) ? finishDiagnosticStage : prepared.memoryStage.flowId === "mb-upgrade" ? finishMemoryUpgradeStage : finishMemoryStage)(context, { projectRoot, runId, stage, bytes: prepared.memoryStage.bytes,
2036
+ hookEventId: hookEventId ?? (currentAssignedLifecycle(context) ? "" : findRecentMatchingHookEvent(context, {
1905
2037
  projectId: requireProjectByRoot(context, resolveProjectRoot(projectRoot)).id,
1906
2038
  matchKey: entityReferenceVariants(runId).map(reference => stageLifecycleMatchKey("stage_finish", reference, stage, projectRoot)),
1907
2039
  errorCode: "trusted_session_binding_required", operation: "Memory stage finish"
1908
- }).eventKey }));
2040
+ }).eventKey) }));
1909
2041
  }
1910
2042
  const protectedLifecycle = (stage === "specify" && isVnextSpecifyRun(context, { projectRoot, runId }))
1911
2043
  || (stage === "protocolize" && isVnextProtocolizeRun(context, { projectRoot, runId }))
@@ -2112,6 +2244,102 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
2112
2244
  if (family === "schema") {
2113
2245
  return prepared.schemaValidation;
2114
2246
  }
2247
+ if (family === "delivery") {
2248
+ const projectRoot = requiredOption(parsed, "project-root"), project = requireProjectByRoot(context, resolveProjectRoot(projectRoot));
2249
+ const runId = resolveRun(context, project.id, requiredPosition(parsed, 0, "run-id")).id, stage = requiredOption(parsed, "stage");
2250
+ const input = { projectRoot, runId, stage, command: quote(["dd-flow", ...args]) };
2251
+ const selected = command === "inputs" ? readDeliveryStageScope(context, input) : assertDeliveryCommandOwner(context, input);
2252
+ if (command === "checks") {
2253
+ if (!prepared.deliveryArtifact)
2254
+ throw new AppError("cli_input_unprepared", "Delivery artifact was not prepared", 1);
2255
+ const checks = prepareDeliveryChecks(context, { ...input, artifact: prepared.deliveryArtifact });
2256
+ await checks.run();
2257
+ return { ok: true, verification: checks.evidence().receipt };
2258
+ }
2259
+ if (command === "execute") {
2260
+ if (!prepared.deliveryApproval)
2261
+ throw new AppError("cli_input_unprepared", "Delivery approval was not prepared", 1);
2262
+ return executeDeliveryOperation(context, { ...input, approval: prepared.deliveryApproval });
2263
+ }
2264
+ const packet = readDescriptorStageInput(context, selected.scope, selected.bundle);
2265
+ const previous = packet.input.predecessor ? readAcceptedStageData(context, { ...selected.scope, stage: packet.input.predecessor.stage }) : null;
2266
+ const details = previous ? JSON.parse(previous.bytes.toString("utf8")).details : null;
2267
+ const operation = details?.decision && details?.artifact ? deliveryApprovalScope(selected.scope, selected.bundle, { operationId: details.decision.operation_id, binding: details.decision.binding,
2268
+ artifact: { subject_ref: details.artifact.subject_ref, version: details.artifact.version, sha256: details.artifact.sha256 } }) : null;
2269
+ if (command === "inputs")
2270
+ return { flow_id: selected.flowId, run_id: runId, stage, user_inputs: selected.users,
2271
+ user_inputs_sha256: selected.userInputsSha256, operation_scope: operation, scope_sha256: operation ? hybridDigest(operation) : null };
2272
+ if (command === "reconcile") {
2273
+ if (!details?.decision)
2274
+ throw new AppError("delivery_stage_invalid", "Original delivery decision is required", 2, { effect: "no_effect" });
2275
+ const policy = prepareDeliveryProjectBinding(selected.bundle.execution.snapshot().scope.workspace, details.decision.policy, details.decision.binding.selector);
2276
+ if (hybridDigest(policy.binding) !== hybridDigest(details.decision.binding))
2277
+ throw new AppError("delivery_stage_invalid", "Original delivery policy changed", 2, { effect: "no_effect" });
2278
+ return observeDeliveryResult(context, { ...selected.scope, binding: policy.binding,
2279
+ assertCurrent() { assertDeliveryCommandOwner(context, input); policy.assertCurrent(); } });
2280
+ }
2281
+ throw new AppError("usage", "Unknown delivery command", 2);
2282
+ }
2283
+ if (family === "interactive") {
2284
+ const projectRoot = requiredOption(parsed, "project-root"), project = requireProjectByRoot(context, resolveProjectRoot(projectRoot));
2285
+ const runId = resolveRun(context, project.id, requiredOption(parsed, "run")).id;
2286
+ if (command === "integrate")
2287
+ return integrateInteractiveFinish(context, { projectRoot, runId,
2288
+ ...(prepared.interactiveGitAgreement ? { agreement: prepared.interactiveGitAgreement } : {}) });
2289
+ if (command === "correction")
2290
+ return registerInteractiveReviewCorrection(context, { projectRoot, runId, reviewWorkId: requiredOption(parsed, "work") });
2291
+ if (command === "re-review")
2292
+ return registerInteractiveCorrectionReview(context, { projectRoot, runId, correctionWorkId: requiredOption(parsed, "work") });
2293
+ if (command === "checks") {
2294
+ if (!prepared.interactiveChecksProposal)
2295
+ throw new AppError("cli_input_unprepared", "Interactive check selection was not prepared", 1);
2296
+ let checks;
2297
+ try {
2298
+ checks = PreparedInteractiveChecks.prepare(context, { projectRoot, runId,
2299
+ stage: requiredOption(parsed, "stage"), ...prepared.interactiveChecksProposal });
2300
+ }
2301
+ catch (error) {
2302
+ if (isAppError(error) && error.code === "interactive_checks_invalid"
2303
+ && error.details.reason === "invalid_check_selection" && error.details.effect === "no_effect") {
2304
+ Object.assign(error.details, { phase: "prepare", recoverable: true,
2305
+ retry_command: runtimeCommand(context, ["interactive", "checks", "--project-root", projectRoot, "--run", runId,
2306
+ "--stage", requiredOption(parsed, "stage"), "--result-file", requiredOption(parsed, "result-file"), "--json", "--progress-jsonl"]),
2307
+ retry_instruction: "Correct only the rejected check selection JSON: additionalChecks contains unique id,command,purpose entries; IDs match ^CHK-[A-Za-z0-9-]{1,64}$ and must not collide with policy checks. No plan or check execution was retained by this call. Keep existing obligations and use this exact retry_command; this does not authorize replay of executed checks or bypass other refusals." });
2308
+ }
2309
+ throw error;
2310
+ }
2311
+ return checks.execute(context).then(receipts => ({ plan_sha256: checks.sha256, plan: checks.value(), receipts }));
2312
+ }
2313
+ if (command === "register") {
2314
+ const bundle = readFlowRunExecutionBundle(context, { projectRoot, runId });
2315
+ if (!bundle || bundle.manifest.flow_id !== "interactive")
2316
+ throw new AppError("interactive_stage_invalid", "Bound interactive RUN required", 2, { effect: "no_effect" });
2317
+ return registerInteractiveStageGraph(context, { projectRoot, runId, stage: requiredOption(parsed, "stage"),
2318
+ gitExecutable: readInteractiveWorkGit(bundle).git_executable });
2319
+ }
2320
+ if (command === "git-inputs")
2321
+ return observeInteractiveOriginalGitInputs(context, { projectRoot, runId, stage: requiredOption(parsed, "stage") });
2322
+ if (command === "inputs" || command === "turn" || command === "finish" || command === "scope") {
2323
+ const bundle = readFlowRunExecutionBundle(context, { projectRoot, runId });
2324
+ if (!bundle || bundle.manifest.flow_id !== "interactive")
2325
+ throw new AppError("interactive_stage_invalid", "Bound interactive RUN required", 2, { effect: "no_effect" });
2326
+ const scope = { projectId: project.id, runId };
2327
+ if (command === "inputs")
2328
+ return readInteractiveUserInputs(context, scope, bundle);
2329
+ if (command === "scope") {
2330
+ if (!prepared.interactiveScopeProposal)
2331
+ throw new AppError("cli_input_unprepared", "Interactive scope proposal was not prepared", 1);
2332
+ const result = PreparedInteractiveMutationScope.prepare(context, scope, bundle, prepared.interactiveScopeProposal).retain(context);
2333
+ return { changed: result.changed, scope_revision: result.scope.revision, user_inputs_sha256: result.scope.inputs.sha256,
2334
+ baseline_sha256: result.scope.baseline.sha256, paths: result.scope.active_paths, needs_scope_refresh: result.scope.needs_scope_refresh };
2335
+ }
2336
+ if (!prepared.interactiveInputBytes)
2337
+ throw new AppError("cli_input_unprepared", "Interactive user bytes were not prepared", 1);
2338
+ return deliverInteractiveUserInput(context, scope, bundle, { projectRoot, intakeFile: requiredOption(parsed, "intake-file"),
2339
+ requestId: requiredOption(parsed, "request-id"), kind: command, bytes: prepared.interactiveInputBytes,
2340
+ expectedInputsSha256: requiredOption(parsed, "expected-inputs-sha256") });
2341
+ }
2342
+ }
2115
2343
  if (family === "memory") {
2116
2344
  return dispatchMemory(context, command, parsed, prepared);
2117
2345
  }
@@ -2502,6 +2730,32 @@ function dispatchMemory(context, command, parsed, prepared) {
2502
2730
  }
2503
2731
  if (command === "upgrade" && subcommand === "publish")
2504
2732
  return publishMemoryUpgradeFromStage(context, scope());
2733
+ if (command === "distill" && subcommand === "inputs") {
2734
+ const inputs = readDistillUserInputs(context, scope());
2735
+ return { ...inputs, user_inputs_sha256: hybridDigest(inputs) };
2736
+ }
2737
+ if (command === "fix" && subcommand === "context") {
2738
+ const intake = readMemoryFixSourceIntake(context, scope()), users = readMemoryFixUserInputs(context, scope());
2739
+ return { ...intake, user_inputs: users, user_inputs_sha256: hybridDigest(users) };
2740
+ }
2741
+ if (command === "fix" && subcommand === "scope") {
2742
+ const proposal = prepared.memoryFixProposal;
2743
+ if (!proposal || Object.keys(proposal).sort().join() !== "routing,write_scope")
2744
+ throw new AppError("usage", "Repair scope proposal requires routing and write_scope", 2, { effect: "no_effect" });
2745
+ return prepareMemoryFixScopeEvidence(context, { ...scope(), routing: proposal.routing, writeScope: proposal.write_scope }).snapshot();
2746
+ }
2747
+ if (command === "fix" && subcommand === "publish") {
2748
+ if (!prepared.memoryFixProposal)
2749
+ throw new AppError("cli_input_unprepared", "Repair proposal was not prepared", 1);
2750
+ return prepareMemoryFixPublication(context, { ...scope(), proposal: prepared.memoryFixProposal }).apply();
2751
+ }
2752
+ if (command === "fix" && subcommand === "integrate")
2753
+ return integrateMemoryFixFinish(context, { ...scope(), ...(prepared.memoryFixProposal ? { agreement: prepared.memoryFixProposal } : {}) });
2754
+ if (command === "distill" && subcommand === "publish") {
2755
+ if (!prepared.memoryOperationBytes)
2756
+ throw new AppError("cli_input_unprepared", "Distillation proposal bytes were not prepared", 1);
2757
+ return publishDistillFromStage(context, { ...scope(), bytes: prepared.memoryOperationBytes });
2758
+ }
2505
2759
  if (command === "verify" && subcommand === "checks")
2506
2760
  return runMemoryVerificationChecks(context, scope());
2507
2761
  if (command === "review" && subcommand === "register")
package/dist/cli.js CHANGED
@@ -53,12 +53,26 @@ if (args[0] === "upgrade" || args[0] === "flow" && args[1] === "mb-upgrade") {
53
53
  const { runMemoryUpgradeCli } = await import("./cli/memory-upgrade.js");
54
54
  process.exit(await runMemoryUpgradeCli(args, process.env));
55
55
  }
56
- if (args[0] === "review" || args[0] === "flow" && ["mb-audit", "project-review"].includes(args[1] ?? "")) {
56
+ if (args[0] === "review" || args[0] === "flow" && ["mb-audit", "project-review", "mb-distill", "review-fix"].includes(args[1] ?? "")) {
57
57
  publishSetup('ingress_entered');
58
58
  const { runDiagnosticCli } = await import("./cli/diagnostic.js");
59
59
  publishSetup('imports_ready');
60
60
  process.exit(await runDiagnosticCli(args, process.env));
61
61
  }
62
+ if (args[0] === "flow" && args[1] === "mb-fix") {
63
+ publishSetup('ingress_entered');
64
+ const { runMemoryFixCli } = await import("./cli/memory-fix.js");
65
+ publishSetup('imports_ready');
66
+ process.exit(await runMemoryFixCli(args, process.env));
67
+ }
68
+ if (args[0] === "flow" && args[1] === "interactive") {
69
+ const { runInteractiveCli } = await import("./cli/interactive.js");
70
+ process.exit(await runInteractiveCli(args, process.env));
71
+ }
72
+ if (args[0] === "flow" && ["release", "deploy", "publish"].includes(args[1] ?? "")) {
73
+ const { runDeliveryCli } = await import("./cli/delivery.js");
74
+ process.exit(await runDeliveryCli(args, process.env));
75
+ }
62
76
  if (args.slice(0, 3).join(" ") === "runtime storage admit") {
63
77
  const { runMemoryStorageAdmissionCli } = await import("./cli/memory-storage-admission.js");
64
78
  process.exit(runMemoryStorageAdmissionCli(args));
@@ -75,10 +89,10 @@ if (args.slice(0, 3).join(" ") === "runtime flow admit") {
75
89
  const { runMemoryFlowAdmissionCli } = await import("./cli/memory-flow-admission.js");
76
90
  process.exit(await runMemoryFlowAdmissionCli(args));
77
91
  }
78
- const managedHook = Boolean(process.env.DD_FLOW_CODEX_STATE_DIR) && args.slice(0, 3).join(" ") === "codex hook handle";
92
+ const codexHook = args.slice(0, 3).join(" ") === "codex hook handle";
79
93
  const exitCode = isRuntimeMaintenanceIngress(args, process.env)
80
94
  ? await runRuntimeMaintenanceIngress(args)
81
- : managedHook
95
+ : codexHook
82
96
  ? await (await import("./cli/hook-ingress.js")).runHookIngress(args)
83
97
  : isNativeHookIngress(args)
84
98
  ? await (await import("./cli/native-hook-ingress.js")).runNativeHookIngress(args)