@deksden-com/dd-flow-cli 0.9.0-beta.136 → 0.9.0-beta.138

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 (230) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +9 -0
  3. package/dist/build-info.json +6 -6
  4. package/dist/cli/argument-values.js +5 -5
  5. package/dist/cli/command-inputs.js +89 -20
  6. package/dist/cli/command-metadata.js +56 -3
  7. package/dist/cli/command-option-descriptions.js +5 -0
  8. package/dist/cli/executor-onboarding.js +8 -3
  9. package/dist/cli/flows.js +29 -0
  10. package/dist/cli/help.js +240 -6
  11. package/dist/cli/input-preparation.js +54 -5
  12. package/dist/cli/memory-flow-admission.js +44 -0
  13. package/dist/cli/memory-init-invocation.js +78 -0
  14. package/dist/cli/memory-init.js +240 -0
  15. package/dist/cli/memory-storage-admission.js +53 -0
  16. package/dist/cli/native-hook-ingress.js +1 -1
  17. package/dist/cli/response-file.js +2 -0
  18. package/dist/cli/run-cli.js +283 -160
  19. package/dist/cli/setup.js +9 -7
  20. package/dist/cli.js +54 -2
  21. package/dist/domain/stage-handler-identities.js +20 -0
  22. package/dist/harness-runtime/DD-ZCODE.md +13 -0
  23. package/dist/harness-runtime/bin/dd-opencode.mjs +3 -3
  24. package/dist/harness-runtime/lib/daemon-operations.d.mts +1 -0
  25. package/dist/harness-runtime/lib/daemon-operations.mjs +4 -3
  26. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +4 -2
  27. package/dist/harness-runtime/lib/dd-codex-daemon.mjs +11 -5
  28. package/dist/harness-runtime/lib/dd-codex.mjs +22 -10
  29. package/dist/harness-runtime/lib/dd-droid-daemon.mjs +2 -1
  30. package/dist/harness-runtime/lib/dd-droid.mjs +2 -1
  31. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +4 -2
  32. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +20 -5
  33. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +45 -10
  34. package/dist/harness-runtime/lib/dd-zcode.mjs +7 -3
  35. package/dist/harness-runtime/lib/delegation-instructions.mjs +5 -3
  36. package/dist/harness-runtime/lib/lifecycle-command.mjs +1 -0
  37. package/dist/harness-runtime/lib/managed-daemon.d.mts +1 -0
  38. package/dist/harness-runtime/lib/managed-daemon.mjs +50 -15
  39. package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
  40. package/dist/harness-runtime/lib/native-hook-command.mjs +1 -1
  41. package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
  42. package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
  43. package/dist/harness-runtime/lib/opencode-plugin.mjs +5 -1
  44. package/dist/harness-runtime/lib/operation-progress.mjs +3 -1
  45. package/dist/runtime/context.js +1 -1
  46. package/dist/schemas/discovery-result.schema.json +184 -0
  47. package/dist/schemas/execution-bundle.schema.json +205 -0
  48. package/dist/schemas/execution-settings.schema.json +162 -0
  49. package/dist/schemas/flow-descriptor.schema.json +54 -0
  50. package/dist/schemas/flow-run.schema.json +22 -0
  51. package/dist/schemas/harness-catalog.schema.json +80 -0
  52. package/dist/schemas/mb-init-compose-result.schema.json +457 -0
  53. package/dist/schemas/mb-init-discover-result.schema.json +500 -0
  54. package/dist/schemas/mb-init-finish-result.schema.json +422 -0
  55. package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
  56. package/dist/schemas/mb-init-review-result.schema.json +396 -0
  57. package/dist/schemas/mb-init-verify-result.schema.json +391 -0
  58. package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
  59. package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
  60. package/dist/schemas/memory-composition-work-result.schema.json +38 -0
  61. package/dist/schemas/memory-repair-work-result.schema.json +49 -0
  62. package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
  63. package/dist/schemas/memory-review-work-result.schema.json +43 -0
  64. package/dist/schemas/model-catalog.schema.json +153 -0
  65. package/dist/schemas/profile-settings.schema.json +122 -0
  66. package/dist/schemas/release-manifest.schema.json +291 -0
  67. package/dist/schemas/run-engine-binding.schema.json +1 -1
  68. package/dist/services/check-runner-evidence.js +51 -4
  69. package/dist/services/cli-operation-classifier.js +8 -47
  70. package/dist/services/code-checks.js +387 -34
  71. package/dist/services/controller-child-observer.js +99 -0
  72. package/dist/services/controller-execution.js +88 -0
  73. package/dist/services/controller-fanout.js +79 -13
  74. package/dist/services/dashboard.js +8 -2
  75. package/dist/services/descriptor-coordinator-session.js +35 -0
  76. package/dist/services/descriptor-root-work.js +53 -0
  77. package/dist/services/descriptor-run-settlement.js +105 -0
  78. package/dist/services/descriptor-run-start.js +449 -0
  79. package/dist/services/descriptor-stage-coordinator.js +197 -0
  80. package/dist/services/descriptor-stage-settlement.js +222 -0
  81. package/dist/services/descriptor-stage-start.js +139 -0
  82. package/dist/services/engines.js +39 -22
  83. package/dist/services/eval-snapshots.js +83 -25
  84. package/dist/services/execution-bundles.js +263 -0
  85. package/dist/services/execution-policy.js +20 -16
  86. package/dist/services/external-work-launch.js +91 -11
  87. package/dist/services/flow-catalog.js +21 -0
  88. package/dist/services/flow-descriptors.js +82 -0
  89. package/dist/services/frozen-engine.js +242 -0
  90. package/dist/services/generic-execution.js +164 -0
  91. package/dist/services/harness-adapter.js +28 -2
  92. package/dist/services/hooks.js +24 -6
  93. package/dist/services/hybrid-contracts.js +31 -3
  94. package/dist/services/ids.js +29 -1
  95. package/dist/services/installation-lock.js +7 -4
  96. package/dist/services/installed-flow-source.js +183 -0
  97. package/dist/services/lifecycle-invocations.js +257 -78
  98. package/dist/services/memory-accepted-composition.js +77 -0
  99. package/dist/services/memory-baseline-preservation.js +65 -0
  100. package/dist/services/memory-completed-correction-wave.js +320 -0
  101. package/dist/services/memory-compose-handler.js +258 -0
  102. package/dist/services/memory-composition-acceptance.js +199 -0
  103. package/dist/services/memory-composition-graph.js +134 -0
  104. package/dist/services/memory-composition-registration.js +146 -0
  105. package/dist/services/memory-composition-work-custody.js +151 -0
  106. package/dist/services/memory-composition-work-results.js +96 -0
  107. package/dist/services/memory-corrected-review-acceptance.js +129 -0
  108. package/dist/services/memory-corrected-review-batch.js +30 -0
  109. package/dist/services/memory-corrected-review-findings.js +106 -0
  110. package/dist/services/memory-corrected-review-inputs.js +210 -0
  111. package/dist/services/memory-corrected-review-projection.js +78 -0
  112. package/dist/services/memory-corrected-review-receipt.js +170 -0
  113. package/dist/services/memory-corrected-review-registration.js +191 -0
  114. package/dist/services/memory-correction-check-receipt.js +219 -0
  115. package/dist/services/memory-correction-input-owner.js +6 -0
  116. package/dist/services/memory-discover-handler.js +104 -0
  117. package/dist/services/memory-finish-evidence.js +435 -0
  118. package/dist/services/memory-finish-handler.js +215 -0
  119. package/dist/services/memory-finish-integration.js +280 -0
  120. package/dist/services/memory-finish-readiness.js +122 -0
  121. package/dist/services/memory-git-integration.js +151 -0
  122. package/dist/services/memory-historical-corrected-review.js +206 -0
  123. package/dist/services/memory-historical-original-review.js +130 -0
  124. package/dist/services/memory-historical-repair-registration.js +99 -0
  125. package/dist/services/memory-historical-second-review.js +128 -0
  126. package/dist/services/memory-init-bootstrap-readiness.js +210 -0
  127. package/dist/services/memory-init-contexts.js +89 -0
  128. package/dist/services/memory-init-controller-start.js +84 -0
  129. package/dist/services/memory-init-engine-release.js +223 -0
  130. package/dist/services/memory-init-git-policy.js +136 -0
  131. package/dist/services/memory-init-lint-capability.js +185 -0
  132. package/dist/services/memory-init-native-capacity.js +241 -0
  133. package/dist/services/memory-init-preflight.js +312 -0
  134. package/dist/services/memory-init-project-bootstrap.js +599 -0
  135. package/dist/services/memory-init-request-candidate.js +157 -0
  136. package/dist/services/memory-init-request-input.js +66 -0
  137. package/dist/services/memory-init-resource-storage.js +125 -0
  138. package/dist/services/memory-init-run-allocation.js +81 -0
  139. package/dist/services/memory-init-run-bundle.js +98 -0
  140. package/dist/services/memory-init-start.js +175 -0
  141. package/dist/services/memory-init-startup-custody.js +80 -0
  142. package/dist/services/memory-init-startup-input.js +240 -0
  143. package/dist/services/memory-init-storage.js +81 -0
  144. package/dist/services/memory-init-stores.js +359 -0
  145. package/dist/services/memory-init-worktrunk-capability.js +172 -0
  146. package/dist/services/memory-layer-publication.js +611 -0
  147. package/dist/services/memory-layer.js +156 -0
  148. package/dist/services/memory-lint-config.js +85 -0
  149. package/dist/services/memory-native-review-copy.js +165 -0
  150. package/dist/services/memory-normal-flow-entry.js +75 -0
  151. package/dist/services/memory-ordinary-defaults.js +112 -0
  152. package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
  153. package/dist/services/memory-preflight-handler.js +259 -0
  154. package/dist/services/memory-repair-current-view.js +299 -0
  155. package/dist/services/memory-repair-document-delta.js +451 -0
  156. package/dist/services/memory-repair-history.js +491 -0
  157. package/dist/services/memory-repair-physical-binding.js +312 -0
  158. package/dist/services/memory-repair-publication-files.js +152 -0
  159. package/dist/services/memory-repair-publication-intent.js +27 -0
  160. package/dist/services/memory-repair-publication-plan.js +160 -0
  161. package/dist/services/memory-repair-publication-source.js +225 -0
  162. package/dist/services/memory-repair-publication.js +794 -0
  163. package/dist/services/memory-repair-registration.js +239 -0
  164. package/dist/services/memory-repair-work-baseline.js +413 -0
  165. package/dist/services/memory-repair-work-completion.js +97 -0
  166. package/dist/services/memory-repair-work-custody.js +73 -0
  167. package/dist/services/memory-repair-work-results.js +89 -0
  168. package/dist/services/memory-repair-workspace.js +252 -0
  169. package/dist/services/memory-repair-writer-copy.js +735 -0
  170. package/dist/services/memory-result-binding.js +173 -0
  171. package/dist/services/memory-retained-review-authority.js +129 -0
  172. package/dist/services/memory-retained-review-results.js +70 -0
  173. package/dist/services/memory-retained-second-baseline.js +102 -0
  174. package/dist/services/memory-retained-second-repairs.js +156 -0
  175. package/dist/services/memory-review-acceptance.js +214 -0
  176. package/dist/services/memory-review-correction-plan.js +171 -0
  177. package/dist/services/memory-review-handler.js +585 -0
  178. package/dist/services/memory-review-inputs.js +200 -0
  179. package/dist/services/memory-review-receipt.js +180 -0
  180. package/dist/services/memory-review-registration.js +108 -0
  181. package/dist/services/memory-review-work-custody.js +124 -0
  182. package/dist/services/memory-review-work-input.js +72 -0
  183. package/dist/services/memory-review-work-results.js +73 -0
  184. package/dist/services/memory-second-corrected-review-inputs.js +165 -0
  185. package/dist/services/memory-second-correction-plan.js +76 -0
  186. package/dist/services/memory-second-repair-baseline.js +91 -0
  187. package/dist/services/memory-second-repair-launch.js +614 -0
  188. package/dist/services/memory-second-repair-registration.js +88 -0
  189. package/dist/services/memory-second-repair-source.js +187 -0
  190. package/dist/services/memory-second-review-acceptance.js +115 -0
  191. package/dist/services/memory-source-observations.js +117 -0
  192. package/dist/services/memory-stage-dispatch.js +28 -0
  193. package/dist/services/memory-stage-results.js +199 -0
  194. package/dist/services/memory-verification-acceptance.js +135 -0
  195. package/dist/services/memory-verification-checks.js +252 -0
  196. package/dist/services/memory-verification-receipt.js +159 -0
  197. package/dist/services/memory-verify-handler.js +135 -0
  198. package/dist/services/memory-work-result-preparation.js +63 -0
  199. package/dist/services/projects.js +17 -2
  200. package/dist/services/recovery-snapshot-database.js +416 -1
  201. package/dist/services/repair-intents.js +1 -1
  202. package/dist/services/review-copy.js +10 -2
  203. package/dist/services/run-control.js +80 -9
  204. package/dist/services/run-controller-capture.js +10 -3
  205. package/dist/services/run-controller-process.js +21 -0
  206. package/dist/services/run-controller-recovery.js +3 -1
  207. package/dist/services/run-controller-state.js +1 -1
  208. package/dist/services/run-controller.js +184 -48
  209. package/dist/services/run-recovery-guard.js +2 -0
  210. package/dist/services/run-recovery.js +145 -5
  211. package/dist/services/run-start-custody.js +177 -0
  212. package/dist/services/runs.js +319 -25
  213. package/dist/services/stage-context.js +9 -1
  214. package/dist/services/stage-handlers.js +74 -0
  215. package/dist/services/stage-lifecycle.js +2 -1
  216. package/dist/services/stage-report-renderer.js +76 -0
  217. package/dist/services/stage-work-graph.js +17 -0
  218. package/dist/services/vnext-code.js +3 -3
  219. package/dist/services/vnext-execution-profile.js +2 -2
  220. package/dist/services/vnext-fanout.js +136 -10
  221. package/dist/services/vnext-merge.js +8 -3
  222. package/dist/services/vnext-plan-review.js +6 -4
  223. package/dist/services/vnext-protocolize.js +60 -2
  224. package/dist/services/work-registry.js +616 -71
  225. package/dist/services/workspace-files.js +1 -1
  226. package/dist/storage/database.js +84 -6
  227. package/dist/storage/writer-contract.js +11 -7
  228. package/package.json +13 -3
  229. package/tools/create-canon-release.mjs +33 -0
  230. package/tools/produce-hybrid-release.mjs +41 -0
@@ -1,4 +1,5 @@
1
1
  import fs from "node:fs";
2
+ import { prepareResponseDestination, writeResponseFile } from "./response-file.js";
2
3
  import { requiredOption, optionalOption, optionalNumber, optionalPositiveNumber } from "./argument-values.js";
3
4
  import { resolveCommandPaths, resolveCommandProjectRoot } from "../services/command-context.js";
4
5
  import { assertAuxiliaryCommandScope, cliManagedInvocationScope, manualRecoveryInvocationScope, assertManualRecoveryInvocationTarget } from "../services/lifecycle-invocations.js";
@@ -12,7 +13,14 @@ import { createContext, createRouterContext } from "../runtime/context.js";
12
13
  import { dispatchNativeHook, isNativeHookIngress } from "./native-hook-ingress.js";
13
14
  import { isRuntimeMaintenance, runtimeMaintenanceDiagnostics, withMaintenanceDiagnosticScope } from "./runtime-maintenance-diagnostics.js";
14
15
  import { migrateStoreWriter } from "../storage/writer-migration.js";
15
- import { helpForArgs } from "./help.js";
16
+ import { resolveHelp } from "./help.js";
17
+ import { renderHumanError, writePreparationError } from "./error-output.js";
18
+ import { runOperatorProfilesCli } from "./operator-profiles.js";
19
+ import { runSetupCli } from "./setup.js";
20
+ import { runCompletionCli } from "./completion-cli.js";
21
+ import { runHarnessesCli } from "./harnesses.js";
22
+ import { runModelsCli } from "./models.js";
23
+ import { parseOutputOptions } from "./output-options.js";
16
24
  import { AppError, errorRecord, isAppError } from "../shared/errors.js";
17
25
  import { entityReferenceVariants } from "../shared/entity-references.js";
18
26
  import { writeJson, parseJsonObject } from "../shared/json.js";
@@ -22,7 +30,7 @@ import { getPlanStatus, preparePlanItemMutation, updatePlanItem } from "../servi
22
30
  import { cancelMergeQueueJob, prepareMergeQueueCancellation, prepareMergeQueueWait, prepareMergeClaim, prepareMergeBundleClaim, claimNextMergeJob, claimMergeJob, claimMergeBundle, completeMergeBundle, prepareMergeBundleCompletion, completeMergeJob, prepareMergeJobCompletion, failMergeBundle, prepareMergeBundleFailure, failMergeJob, prepareMergeJobFailure, getMergeBundleStatus, getMergeQueueStatus, noteMergeJob, prepareMergeJobNote, waitNextMergeJob } from "../services/merge-queue.js";
23
31
  import { getMergeWorkerStatus, oneShotMergeClaim, startMergeWorker, stopProjectMergeWorker } from "../services/merge-worker.js";
24
32
  import { cleanupApply, cleanupScan, prepareCleanupApply } from "../services/cleanup.js";
25
- import { getCodexHomeStatus, getCodexHooksStatus, handleCodexHook, handleAgyEvent, handleDroidEvent, handleGrokEvent, handleOpenCodeEvent, handleZcodeHook, handleZcodeEvent, isolatedDdFlowHomeFromHookStdin, claimBootstrapHookEvent, findRecentMatchingHookEvent, stageStartMatchKey, initCodexHome, prepareCodexHome, prepareCodexHooks, installCodexHooks, planCodexHome, printCodexHomeEnv, printCodexHooks, removeCodexHome, prepareCodexHomeRemoval, removeCodexHooks } from "../services/hooks.js";
33
+ import { getCodexHomeStatus, getCodexHooksStatus, handleCodexHook, handleAgyEvent, handleDroidEvent, handleGrokEvent, handleOpenCodeEvent, handleZcodeHook, handleZcodeEvent, isolatedDdFlowHomeFromHookStdin, claimBootstrapHookEvent, findRecentMatchingHookEvent, stageStartMatchKey, stageLifecycleMatchKey, initCodexHome, prepareCodexHome, prepareCodexHooks, installCodexHooks, planCodexHome, printCodexHomeEnv, printCodexHooks, removeCodexHome, prepareCodexHomeRemoval, removeCodexHooks } from "../services/hooks.js";
26
34
  import { bootstrapWorktree, closeWorktree, createWorktreeRecord, prepareWorktreeCreate, prepareWorktreeBootstrap, prepareWorktreeClose, getWorktreeStatus, planWorktree } from "../services/worktrees.js";
27
35
  import { acquireLaneLock, cancelLaneWaiter, prepareLaneWaiterCancellation, checkLaneWorkspace, getLaneWaiters, getLaneStatus, heartbeatLaneLock, releaseLaneLock, setLaneWorkspace, prepareLaneWorkspace, prepareLaneLock, waitAcquireLaneLock, waitForLaneLock } from "../services/lanes.js";
28
36
  import { getProjectConfigStatus, prepareProjectConfigValue, setProjectConfigValue } from "../services/config.js";
@@ -30,12 +38,12 @@ import { getCanonStatus, registerCanonRoot, resolveCanonRoot, prepareCanonRegist
30
38
  import { getRuntimeStatus } from "../services/status.js";
31
39
  import { getCliVersionReport } from "../services/build-info.js";
32
40
  import { parseCommandArgs } from "../services/lifecycle-command.js";
33
- import { prepareError, prepareJsonFile, prepareJsonSchema, prepareJsonText, prepareTextFile } from "./input-preparation.js";
41
+ import { prepareError, prepareJsonFile, prepareJsonSchema, prepareJsonText, prepareTextFile, prepareFileBytes, readBoundedUtf8Stream } from "./input-preparation.js";
34
42
  import { autoRefreshDashboards, dashboardData, getCmuxStatus, openDashboard, openGlobalDashboard, openProtocolDashboard, refreshAllDashboards, prepareDashboardRefresh, prepareDashboardRender, prepareGlobalDashboardRender, prepareDashboardOptions, refreshDashboard, refreshGlobalDashboard, renderDashboard, renderGlobalDashboard } from "../services/dashboard.js";
35
43
  import { dashboardTargetSummary, preferredDashboardCommand, relatedDashboardCommands, resolveDashboardTarget } from "../services/dashboard-targets.js";
36
44
  import { getFlowSessionStatus, prepareFlowSessionPayload, registerFlowSession, stopFlowSession, stopMergeWorker, syncFlowSessionUsage } from "../services/sessions.js";
37
45
  import { getProtocolBranchContext } from "../services/branch-context.js";
38
- import { attachFlowRunStage, prepareFlowRunStageAttachment, prepareFlowRunStageCompletion, completeFlowRun, prepareFlowRunCompletion, completeFlowRunStage, getFlowRunSessions, getFlowRunTimeline, getStoredFlowRunUsage, getFlowRunFlagsStatus, getFlowRunStatus, getFlowRunConfig, getFlowRunVariables, listFlowRuns, reviseFlowRunFlags, setFlowRunConfig, prepareFlowRunConfig, prepareFlowRunVariable, setFlowRunVariable, startFlowRun, prepareFlowRunStart } from "../services/runs.js";
46
+ import { attachFlowRunStage, readFlowRunExecutionBundle, prepareFlowRunStageAttachment, prepareRawFlowRunStageCompletion, completeFlowRun, prepareFlowRunCompletion, completeFlowRunStage, getFlowRunSessions, getFlowRunTimeline, getStoredFlowRunUsage, getFlowRunFlagsStatus, getFlowRunStatus, getFlowRunConfig, getFlowRunVariables, listFlowRuns, reviseFlowRunFlags, setFlowRunConfig, prepareFlowRunConfig, prepareFlowRunVariable, setFlowRunVariable, startFlowRun, resolveRun, prepareFlowRunStart } from "../services/runs.js";
39
47
  import { previewNextEntityId } from "../services/ids.js";
40
48
  import { validateSchema } from "../services/schema-validation.js";
41
49
  import { preflightMemoryPermissions } from "../services/memory-permissions.js";
@@ -46,21 +54,34 @@ import { requireProjectByRoot } from "../services/projects.js";
46
54
  import { resolveProjectRoot, resolveDdFlowHome } from "../storage/paths.js";
47
55
  import { doctorEngines, bindRunEngine, prepareRunEngineBind, engineInfo, installCurrentEngine, listEngines, resolveEngine, resolveExplicitProjectRoot, resolveOperationProjectRoot, routeArgsThroughEngine } from "../services/engines.js";
48
56
  import { preflightCliCompatibility } from "../services/compatibility-preflight.js";
49
- import { finishVnextSpecifyStage, getVnextWorkStatus, isVnextSpecifyFlow, isVnextSpecifyRun, launchVnextSpecify, prepareVnextSpecifyStart } from "../services/vnext-specify.js";
50
- import { finishVnextProtocolize, isVnextProtocolizeRun, prepareProtocolizeResultPath, prepareVnextProtocolizeStart, startVnextProtocolize } from "../services/vnext-protocolize.js";
51
- import { finishVnextPlan, isVnextPlanRun, startVnextPlan, prepareVnextPlanStart, prepareVnextPlanFinish } from "../services/vnext-plan.js";
52
- import { dispatchVnextPlanReview, finishVnextPlanReview, isVnextPlanReviewRun, prepareVnextPlanReviewStart, recordVnextPlanReviewCapacity, startVnextPlanReview } from "../services/vnext-plan-review.js";
53
- import { addVnextCodeRepair, finishVnextCode, prepareVnextCodeRepair, prepareVnextCodeStart, startVnextCode } from "../services/vnext-code.js";
54
- import { finishVnextCodeReview, isVnextCodeReviewRun, prepareCodeReviewDecision, prepareVnextCodeReviewRepair, prepareVnextCodeReviewStart, startVnextCodeReview } from "../services/vnext-code-review.js";
55
- import { applyVnextMerge, finishVnextMerge, getVnextMergeRequest, isVnextMergeRun, prepareVnextMergeFinish, prepareVnextMergeStart, repairVnextMerge, routeVnextMergeRequest, startVnextMerge } from "../services/vnext-merge.js";
57
+ import { getVnextWorkStatus, isVnextSpecifyFlow, isVnextSpecifyRun, prepareVnextSpecifyStart } from "../services/vnext-specify.js";
58
+ import { isVnextProtocolizeRun, prepareProtocolizeResultPath, prepareVnextProtocolizeStart } from "../services/vnext-protocolize.js";
59
+ import { isVnextPlanRun, prepareVnextPlanStart, prepareVnextPlanFinish } from "../services/vnext-plan.js";
60
+ import { dispatchVnextPlanReview, isVnextPlanReviewRun, prepareVnextPlanReviewStart, recordVnextPlanReviewCapacity } from "../services/vnext-plan-review.js";
61
+ import { addVnextCodeRepair, prepareVnextCodeRepair, prepareVnextCodeStart } from "../services/vnext-code.js";
62
+ import { isVnextCodeReviewRun, prepareCodeReviewDecision, prepareVnextCodeReviewRepair, prepareVnextCodeReviewStart } from "../services/vnext-code-review.js";
63
+ import { applyVnextMerge, getVnextMergeRequest, isVnextMergeRun, prepareVnextMergeFinish, prepareVnextMergeStart, repairVnextMerge, routeVnextMergeRequest } from "../services/vnext-merge.js";
64
+ import { sdlcStageHandlers } from "../services/stage-handlers.js";
65
+ import { startMemoryStage, finishMemoryStage } from "../services/memory-stage-dispatch.js";
66
+ import { bindStageCoordinatorWork } from "../services/work-registry.js";
67
+ import { registerMemoryCompositionFromStage } from "../services/memory-compose-handler.js";
68
+ import { runMemoryVerificationChecks } from "../services/memory-verify-handler.js";
69
+ import { registerMemoryReviewFromStage, collectMemoryInitialReviewFromStage } from "../services/memory-review-handler.js";
70
+ import { PreparedRetainedMemoryReviewAuthority } from "../services/memory-retained-review-authority.js";
71
+ import { PreparedRetainedMemoryReviewResults } from "../services/memory-retained-review-results.js";
72
+ import { registerMemoryCorrectionsFromStage, registerMemorySecondCorrectionsFromStage, runMemoryCorrectionChecksFromStage, runMemorySecondCorrectionChecksFromStage, registerCorrectedMemoryReviewFromStage, registerSecondCorrectedMemoryReviewFromStage, collectCorrectedMemoryReviewFromStage, collectSecondCorrectedMemoryReviewFromStage } from "../services/memory-review-handler.js";
73
+ import { integrateMemoryFinishFromStage, registerMemoryFinishEvidenceFromStage } from "../services/memory-finish-handler.js";
74
+ import { registerMemoryRepairBaselineFromStage, registerMemorySecondRepairBaselineFromStage, reserveMemoryRepairWriterCopyFromStage, reserveMemorySecondRepairCopyFromStage, materializeMemoryRepairWriterCopyFromStage, materializeMemorySecondRepairCopyFromStage, prepareMemoryRepairDispatchFromStage, prepareMemorySecondRepairDispatchFromStage, registerMemoryRepairCurrentViewFromStage, registerMemorySecondRepairCurrentViewFromStage, registerMemoryRepairPublicationSourceFromStage, reserveMemoryRepairPublicationAgainstSourceFromStage, reserveMemorySecondRepairPublicationFromStage, applyMemoryRepairPublicationFromStage, applyMemorySecondRepairPublicationFromStage, finishMemoryRepairPublicationFromStage, finishMemorySecondRepairPublicationFromStage } from "../services/memory-review-handler.js";
56
75
  import { mergeServerStatus, serveMergeRequests, stopMergeServer } from "../services/merge-server.js";
57
- import { getVnextFanoutStatus, observeVnextNativeChildren, prepareNativeObservations, reconcileVnextFanout } from "../services/vnext-fanout.js";
58
- import { pauseStageForUser, resumeStageAfterUser, prepareStagePause, prepareStageResume } from "../services/stage-pause.js";
76
+ import { getVnextFanoutStatus, memoryStageFanoutDescriptor, observeVnextNativeChildren, prepareNativeObservations, reconcileVnextFanout } from "../services/vnext-fanout.js";
77
+ import { pauseStageForUser, resumeStageAfterUser, prepareStagePause, prepareStageResume, stagePauseCommand } from "../services/stage-pause.js";
78
+ import { runtimeCommand } from "../services/runtime-command.js";
79
+ import { managedLifecycleCommand } from "../services/lifecycle-invocations.js";
59
80
  import { blockStageForRuntime, unblockStageAfterRuntimeRepair, prepareStageRuntimeBlock, prepareStageRuntimeUnblock } from "../services/stage-blocker.js";
60
81
  import { classifyCliOperation, requiresExplicitUpgradeAuthorization } from "../services/cli-operation-classifier.js";
61
82
  import { prepareWorkerPrompt, renderWorkerPrompt } from "../services/prompts.js";
62
83
  import { finishStage, prepareStageFinish, startStage, prepareLegacyStageStart } from "../services/stage-lifecycle.js";
63
- import { addWorkBatch, prepareWorkBatch, prepareWorkDeps, prepareWorkDelete, prepareWorkSettlement, prepareWorkRetry, assertStageLifecycleOwner, assertWorkLifecycleOwner, cancelWork, deleteWork, failWork, finishWork, listWorks, mutateWorkDeps, prepareWorkResult, retryWork, showWork, startWork } from "../services/work-registry.js";
84
+ import { addWorkBatch, prepareWorkBatch, prepareWorkDeps, prepareWorkDelete, prepareWorkSettlement, prepareWorkRetry, assertStageLifecycleOwner, assertWorkLifecycleOwner, cancelWork, deleteWork, failWork, finishWork, listWorks, mutateWorkDeps, prepareWorkResult, workResultByteLimit, retryWork, showWork, startWork } from "../services/work-registry.js";
64
85
  import { launchExternalWork } from "../services/external-work-launch.js";
65
86
  import { createEvalBootstrapSnapshot, prepareEvalBootstrapSnapshot, createEvalRunSnapshot, prepareEvalRunSnapshotCreation, prepareVnextSpecifyRun, prepareEvalRunRestore, prepareEvalBootstrapRestore, restoreEvalBootstrapSnapshot, restoreEvalRunSnapshot } from "../services/eval-snapshots.js";
66
87
  import { forkRunFromSnapshot, prepareRunFork } from "../services/run-fork.js";
@@ -89,6 +110,21 @@ export async function runCli(args, io = defaultIo, env = process.env) {
89
110
  return withMaintenanceDiagnosticScope(() => runCliRequest(args, io, env));
90
111
  }
91
112
  async function runCliRequest(args, io, env) {
113
+ try {
114
+ const help = resolveHelp(args);
115
+ if (help) {
116
+ if (help.json)
117
+ writeJson(io.stdout, help.data);
118
+ else
119
+ io.stdout.write(`${help.text}\n`);
120
+ return 0;
121
+ }
122
+ }
123
+ catch (error) {
124
+ const record = errorRecord(error);
125
+ writePreparationError(io, args, record);
126
+ return record.exitCode;
127
+ }
92
128
  let output;
93
129
  try {
94
130
  output = parseOutputOptions(args);
@@ -114,7 +150,7 @@ async function runCliRequest(args, io, env) {
114
150
  catch (persistence) {
115
151
  rejection.details.lifecycle_diagnostic_error = String(persistence);
116
152
  }
117
- writeJson(io.stderr, { ok: false, error: errorRecord(rejection) });
153
+ writePreparationError(io, args, errorRecord(rejection));
118
154
  return rejection.exitCode;
119
155
  }
120
156
  const progress = progressForCommand(output.args);
@@ -132,11 +168,16 @@ async function runCliRequest(args, io, env) {
132
168
  io.stdout.write(`dd-flow ${payload.cli.version}\n`);
133
169
  return 0;
134
170
  }
135
- const help = helpForArgs(output.args);
136
- if (help) {
137
- io.stdout.write(`${help}\n`);
138
- return 0;
139
- }
171
+ if (output.args[0] === "completion")
172
+ return runCompletionCli(args, io);
173
+ if (output.args[0] === "setup")
174
+ return runSetupCli(args, env, io);
175
+ if (output.args[0] === "harnesses")
176
+ return runHarnessesCli(args, env, io);
177
+ if (output.args[0] === "models")
178
+ return runModelsCli(args, io);
179
+ if (output.args[0] === "profiles")
180
+ return runOperatorProfilesCli(args, env, io);
140
181
  const suppliedInvocationId = optionalOption(parseArgs(output.args.slice(2)), "invocation-id");
141
182
  if (isNativeHookIngress(output.args)) {
142
183
  writeJson(io.stdout, await dispatchNativeHook(output.args, await readStdin(io.stdin), env));
@@ -436,6 +477,8 @@ async function runCliRequest(args, io, env) {
436
477
  if (invocationSettlement && error.details.effect !== "committed") {
437
478
  try {
438
479
  if (isAppError(error)) {
480
+ delete error.details.retry_command;
481
+ delete error.details.retry_instruction;
439
482
  const settled = errorRecord(error);
440
483
  settleLifecycleRejection(invocationSettlement.context, invocationSettlement.id, settled);
441
484
  // Serialization owns a copy. Publish the committed settlement, not
@@ -446,6 +489,8 @@ async function runCliRequest(args, io, env) {
446
489
  settleLifecycleInvocation(invocationSettlement.context, invocationSettlement.id, { error: { code: "unexpected", message: String(error), exitCode: 1, details: {} } });
447
490
  }
448
491
  catch (persistenceError) {
492
+ if (isAppError(error))
493
+ error.details.recoverable = false;
449
494
  io.stderr.write(`Invocation settlement persistence failed: ${String(persistenceError)}\n`);
450
495
  }
451
496
  }
@@ -478,7 +523,7 @@ async function runCliRequest(args, io, env) {
478
523
  else if (output.json)
479
524
  writeJson(io.stderr, visible);
480
525
  else
481
- io.stderr.write(renderHumanError(payload));
526
+ io.stderr.write(renderHumanError(payload, args));
482
527
  return isAppError(error) ? error.exitCode : 1;
483
528
  }
484
529
  finally {
@@ -540,115 +585,6 @@ function databaseModeForCommand(args, classification) {
540
585
  return "read_existing";
541
586
  return "initialize";
542
587
  }
543
- function renderHumanError(payload) {
544
- const lines = [`dd-flow: ${payload.error.message}`];
545
- const details = recordObject(payload.error.details);
546
- const compatibility = recordObject(details?.compatibility);
547
- const remediation = recordObject(details?.remediation);
548
- if (compatibility) {
549
- lines.push(`Compatibility: ${String(compatibility.verdict ?? "unknown")} (${String(compatibility.engine_resolution ?? "unknown")})`);
550
- if (compatibility.blocked_operation)
551
- lines.push(`Blocked operation: ${String(compatibility.blocked_operation)}`);
552
- if (compatibility.install_hint)
553
- lines.push(`Install compatible engine: ${String(compatibility.install_hint)}`);
554
- }
555
- if (remediation?.mb_upgrade_mode)
556
- lines.push(`Upgrade mode: ${String(remediation.mb_upgrade_mode)}`);
557
- if (details?.preferred_command)
558
- lines.push(`Preferred command: ${String(details.preferred_command)}`);
559
- const related = Array.isArray(details?.related_commands) ? details.related_commands.map(String) : [];
560
- if (related.length > 0) {
561
- lines.push("", "Related commands:");
562
- for (const command of related)
563
- lines.push(` ${command}`);
564
- }
565
- return `${lines.join("\n")}\n`;
566
- }
567
- function parseOutputOptions(args) {
568
- const stripped = [];
569
- let json = false;
570
- let progressJsonl = false;
571
- let responseFile = null;
572
- for (let index = 0; index < args.length; index += 1) {
573
- const arg = args[index];
574
- if (arg === undefined)
575
- continue;
576
- if (arg === "--json") {
577
- json = true;
578
- continue;
579
- }
580
- if (arg === "--progress-jsonl") {
581
- progressJsonl = true;
582
- continue;
583
- }
584
- if (arg === "--response-file") {
585
- if (responseFile !== null)
586
- throw new AppError("usage", "--response-file may be supplied only once", 2);
587
- const file = args[++index];
588
- if (!file?.trim() || file.startsWith("--"))
589
- throw new AppError("usage", "--response-file requires a path", 2);
590
- responseFile = file;
591
- continue;
592
- }
593
- stripped.push(arg);
594
- }
595
- if (responseFile && !json)
596
- throw new AppError("usage", "--response-file requires --json", 2);
597
- const hookJsonOnly = stripped[0] === "codex" && stripped[1] === "hook" && stripped[2] === "handle";
598
- return { json: json || hookJsonOnly, progressJsonl, args: stripped, hookJsonOnly, responseFile };
599
- }
600
- /** Validate the response destination without creating it. The response is an
601
- * optional publication, but a known-bad destination should never be found
602
- * only after a successful lifecycle mutation. */
603
- function prepareResponseDestination(value) {
604
- const file = path.resolve(value);
605
- const parent = path.dirname(file);
606
- try {
607
- let ancestor = parent;
608
- for (;;) {
609
- try {
610
- if (!fs.statSync(ancestor).isDirectory())
611
- throw new AppError("response_file_parent_invalid", "--response-file parent must be a directory", 2, { file, parent });
612
- break;
613
- }
614
- catch (error) {
615
- if (error.code !== "ENOENT" || path.dirname(ancestor) === ancestor)
616
- throw error;
617
- ancestor = path.dirname(ancestor);
618
- }
619
- }
620
- if (fs.existsSync(file) && !fs.statSync(file).isFile())
621
- throw new AppError("response_file_invalid", "--response-file must name a regular file", 2, { file });
622
- }
623
- catch (error) {
624
- return prepareError(error, { parameter: "response-file", file, parent });
625
- }
626
- }
627
- /** Persist the complete machine response for harnesses that cap tool output.
628
- * The visible response keeps routing fields but omits the potentially large
629
- * rendered prompt; an agent can safely read the named file without rerunning
630
- * the lifecycle command. */
631
- function writeResponseFile(payload, output) {
632
- if (!output.responseFile)
633
- return payload;
634
- const file = path.resolve(output.responseFile);
635
- try {
636
- fs.mkdirSync(path.dirname(file), { recursive: true });
637
- const temporary = `${file}.tmp-${process.pid}-${crypto.randomUUID()}`;
638
- fs.writeFileSync(temporary, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
639
- fs.renameSync(temporary, file);
640
- }
641
- catch (error) {
642
- // The lifecycle mutation may already be accepted. Do not retry it just
643
- // because its optional full-response file could not be written.
644
- return { ...(payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { ok: true, result: payload }), response_file: file, response_file_error: String(error) };
645
- }
646
- if (!payload || typeof payload !== "object" || Array.isArray(payload))
647
- return { ok: true, response_file: file };
648
- const visible = { ...payload, response_file: file };
649
- delete visible.worker_prompt_markdown;
650
- return visible;
651
- }
652
588
  function progressForCommand(args) {
653
589
  const [family, command, subcommand] = args;
654
590
  if (family === "merge-queue" && command === "wait-next") {
@@ -936,7 +872,7 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
936
872
  if (route.key === "run attach-stage")
937
873
  prepareFlowRunStageAttachment(context, stageAttachmentInput(parsed));
938
874
  if (route.key === "run complete-stage")
939
- prepareFlowRunStageCompletion(context, stageCompletionInput(parsed));
875
+ prepareRawFlowRunStageCompletion(context, stageCompletionInput(parsed));
940
876
  if (route.key === "run override")
941
877
  prepareFlowRunCompletion(context, runOverrideInput(parsed));
942
878
  if (route.key === "engine bind-run")
@@ -1053,7 +989,7 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
1053
989
  }
1054
990
  if (route.key === "run snapshot bootstrap create") {
1055
991
  try {
1056
- prepareEvalBootstrapSnapshot(context, { projectRoot: requiredOption(parsed, "project-root"), output: requiredOption(parsed, "output") });
992
+ prepareEvalBootstrapSnapshot(context, { projectRoot: requiredOption(parsed, "project-root"), output: requiredOption(parsed, "output"), flow: optionalOption(parsed, "flow") });
1057
993
  }
1058
994
  catch (error) {
1059
995
  return prepareError(error, { parameter: "project-root/output" });
@@ -1175,7 +1111,9 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
1175
1111
  if (route.key === "work add-batch") {
1176
1112
  const file = requiredOption(parsed, "file");
1177
1113
  try {
1178
- prepared.workBatch = prepareWorkBatch(context, { parentWorkId: requiredOption(parsed, "parent"), file });
1114
+ prepared.workBatch = prepareWorkBatch(context, { parentWorkId: requiredOption(parsed, "parent"), file,
1115
+ ...(optionalOption(parsed, "stage") ? { stage: optionalOption(parsed, "stage") } : {}),
1116
+ ...(optionalOption(parsed, "request-key") ? { requestKey: optionalOption(parsed, "request-key") } : {}) });
1179
1117
  }
1180
1118
  catch (error) {
1181
1119
  return prepareError(error, { parameter: "file/parent", file });
@@ -1264,6 +1202,21 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
1264
1202
  throw new AppError("usage", "stage start requires --context-file together with --context-sha256", 2);
1265
1203
  if ([hasOption(parsed, "intake-file"), hasOption(parsed, "intake-stdin"), Boolean(contextFile)].filter(Boolean).length > 1)
1266
1204
  throw new AppError("usage", "Use exactly one of --intake-file, --intake-stdin or --context-file", 2);
1205
+ if (!hasOption(parsed, "bootstrap")) {
1206
+ const bundle = readFlowRunExecutionBundle(context, { projectRoot: requiredOption(parsed, "project-root"), runId: requiredPosition(parsed, 0, "run-id") });
1207
+ if (bundle)
1208
+ prepared.stageBindingBundle = { stage, bundle, ...(contextSha256 ? { contextSha256 } : {}) };
1209
+ if (bundle?.descriptor.descriptor.id === "mb-init") {
1210
+ bundle.descriptor.stage(stage);
1211
+ if (hasOption(parsed, "dir"))
1212
+ throw new AppError("usage", "Memory stage layout belongs to its frozen descriptor", 2);
1213
+ const loaded = contextFile && contextSha256 ? loadExternalStageContext({ file: contextFile, expectedSha256: contextSha256, stage }) : undefined;
1214
+ if (loaded)
1215
+ prepared.stageStart = { externalContext: loaded };
1216
+ prepared.memoryStage = { operation: "start", bytes: loaded ? Buffer.from(loaded.bytes) : Buffer.alloc(0) };
1217
+ return prepared;
1218
+ }
1219
+ }
1267
1220
  if (contextFile && contextSha256) {
1268
1221
  try {
1269
1222
  prepared.stageStart = { externalContext: loadExternalStageContext({ file: contextFile, expectedSha256: contextSha256, stage }) };
@@ -1354,7 +1307,8 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
1354
1307
  const resultStdin = hasOption(parsed, "result-stdin");
1355
1308
  if (Boolean(resultFile) === resultStdin)
1356
1309
  throw new AppError("usage", "work finish requires exactly one of --result-file or --result-stdin", 2);
1357
- prepared.workFinish = { result: resultFile ? prepareTextFile(resultFile, "Work result").text : await readStdin(io.stdin) };
1310
+ const maxBytes = workResultByteLimit(context, requiredPosition(parsed, 0, "work-id"));
1311
+ prepared.workFinish = { result: resultFile ? prepareTextFile(resultFile, "Work result", maxBytes).text : await readStdin(io.stdin, maxBytes) };
1358
1312
  prepareWorkResult(context, requiredPosition(parsed, 0, "work-id"), prepared.workFinish.result);
1359
1313
  }
1360
1314
  if (family === "stage" && command === "fanout" && requiredPosition(parsed, 0, "fanout action") === "reconcile") {
@@ -1363,6 +1317,13 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
1363
1317
  if (family === "stage" && command === "native" && requiredPosition(parsed, 0, "native action") === "observe") {
1364
1318
  prepared.observations = prepareNativeObservations(prepareJsonFile(requiredOption(parsed, "observations-file"), "native observations").value);
1365
1319
  }
1320
+ if (family === "memory" && (["compose", "corrections"].includes(command ?? "") && parsed.positional[0] === "register"
1321
+ || command === "repair" && parsed.positional[0] === "publication-reserve")) {
1322
+ const bytes = prepareFileBytes(requiredOption(parsed, "result-file"), `Memory ${command} result`, 1024 * 1024).bytes;
1323
+ if (!bytes.length || bytes.length > 1024 * 1024)
1324
+ throw new AppError("usage", "Memory operation result exceeds its byte bound", 2);
1325
+ prepared.memoryOperationBytes = bytes;
1326
+ }
1366
1327
  if (family !== "stage" || command !== "finish")
1367
1328
  return prepared;
1368
1329
  const projectRoot = requiredOption(parsed, "project-root");
@@ -1378,6 +1339,21 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
1378
1339
  const semanticFile = optionalOption(parsed, "semantic-file") ?? optionalOption(parsed, "data");
1379
1340
  const resultFile = optionalOption(parsed, "result-file") ?? semanticFile;
1380
1341
  const runtime = run(projectRoot, runId);
1342
+ if (JSON.parse(runtime.indexJson).execution_bundle?.flow_id === "mb-init") {
1343
+ const bundle = readFlowRunExecutionBundle(context, { projectRoot, runId });
1344
+ if (!bundle || bundle.descriptor.descriptor.id !== "mb-init")
1345
+ throw new AppError("cli_input_unprepared", "Memory RUN bundle is unavailable", 1);
1346
+ bundle.descriptor.stage(stage);
1347
+ if (["dir", "outcome", "decision-file", "verification-file", "retry-check", "reason", "reason-file", "request", "work"].some(option => hasOption(parsed, option)))
1348
+ throw new AppError("usage", "Memory stage finish requires its registered JSON result, not legacy result options", 2);
1349
+ if (Boolean(resultFile) === resultStdin)
1350
+ throw new AppError("usage", "Memory stage finish requires exactly one result input", 2);
1351
+ const bytes = resultStdin ? Buffer.from(await readStdin(io.stdin, 1024 * 1024)) : prepareFileBytes(resultFile, "Memory stage result", 1024 * 1024).bytes;
1352
+ if (!bytes.length || bytes.length > 1024 * 1024)
1353
+ throw new AppError("usage", "Memory stage result exceeds its byte bound", 2);
1354
+ prepared.memoryStage = { operation: "finish", bytes };
1355
+ return prepared;
1356
+ }
1381
1357
  const terminalReplay = (name) => {
1382
1358
  let index;
1383
1359
  try {
@@ -1649,9 +1625,10 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
1649
1625
  }
1650
1626
  if (family === "stage" && command === "fanout") {
1651
1627
  const action = requiredPosition(parsed, 0, "fanout action");
1652
- const runId = requiredPosition(parsed, 1, "run-id");
1653
1628
  const stage = requiredOption(parsed, "stage");
1654
1629
  const projectRoot = requiredScopeProjectRoot(scopeProjectRoot, "stage fanout");
1630
+ const project = requireProjectByRoot(context, resolveProjectRoot(projectRoot));
1631
+ const runId = resolveRun(context, project.id, requiredPosition(parsed, 1, "run-id")).id;
1655
1632
  if (action === "status")
1656
1633
  return getVnextFanoutStatus(context, { projectRoot, runId, stage });
1657
1634
  if (action === "reconcile")
@@ -1687,7 +1664,9 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
1687
1664
  });
1688
1665
  }
1689
1666
  if (family === "work" && command === "add-batch") {
1690
- return addWorkBatch(context, { parentWorkId: requiredOption(parsed, "parent"), file: requiredOption(parsed, "file"), prepared: prepared.workBatch });
1667
+ return addWorkBatch(context, { parentWorkId: requiredOption(parsed, "parent"), file: requiredOption(parsed, "file"), prepared: prepared.workBatch,
1668
+ ...(optionalOption(parsed, "stage") ? { stage: optionalOption(parsed, "stage") } : {}),
1669
+ ...(optionalOption(parsed, "request-key") ? { requestKey: optionalOption(parsed, "request-key") } : {}) });
1691
1670
  }
1692
1671
  if (family === "work" && command === "ls") {
1693
1672
  return listWorks(context, { ...(optionalOption(parsed, "run") ? { runId: optionalOption(parsed, "run") } : {}), ...(optionalOption(parsed, "parent") ? { parentWorkId: optionalOption(parsed, "parent") } : {}), ...(optionalOption(parsed, "status") ? { status: optionalOption(parsed, "status") } : {}), ...(hasOption(parsed, "ready") ? { ready: true } : {}), ...(hasOption(parsed, "include-results") ? { includeResults: true } : {}), ...(optionalOption(parsed, "limit") ? { limit: Number(optionalOption(parsed, "limit")) } : {}) });
@@ -1724,7 +1703,8 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
1724
1703
  const retryReceiptId = optionalOption(parsed, "retry-check"), retryReason = prepared.retryReason;
1725
1704
  if (Boolean(retryReceiptId) !== Boolean(retryReason))
1726
1705
  throw new AppError("usage", "--retry-check and --reason must be supplied together", 2);
1727
- const result = prepared.workFinish?.result ?? (resultFile ? prepareTextFile(resultFile, "Work result").text : await readStdin(io.stdin));
1706
+ const maxBytes = workResultByteLimit(context, workId);
1707
+ const result = prepared.workFinish?.result ?? (resultFile ? prepareTextFile(resultFile, "Work result", maxBytes).text : await readStdin(io.stdin, maxBytes));
1728
1708
  return await finishWork(context, workId, result, commandProgress(io, output), retryReceiptId ? { receiptId: retryReceiptId, reason: retryReason } : undefined);
1729
1709
  }
1730
1710
  if (family === "work" && command === "fail") {
@@ -1738,6 +1718,8 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
1738
1718
  if (family === "work" && command === "retry")
1739
1719
  return retryWork(context, requiredPosition(parsed, 0, "work-id"), requiredOption(parsed, "reason"));
1740
1720
  if (family === "stage" && command === "start") {
1721
+ if (prepared.stageBindingBundle)
1722
+ context = { ...context, stageBindingBundle: prepared.stageBindingBundle };
1741
1723
  const dir = optionalOption(parsed, "dir");
1742
1724
  const bootstrap = hasOption(parsed, "bootstrap");
1743
1725
  const subject = optionalOption(parsed, "subject");
@@ -1755,6 +1737,34 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
1755
1737
  const projectRoot = requiredOption(parsed, "project-root");
1756
1738
  const stage = requiredOption(parsed, "stage");
1757
1739
  const externalContext = prepared.stageStart?.externalContext;
1740
+ if (prepared.memoryStage?.operation === "start") {
1741
+ const runId = requiredPosition(parsed, 0, "run-id");
1742
+ const event = hookEventId ?? findRecentMatchingHookEvent(context, {
1743
+ projectId: requireProjectByRoot(context, resolveProjectRoot(projectRoot)).id,
1744
+ matchKey: entityReferenceVariants(runId).map(reference => stageStartMatchKey(reference, stage, projectRoot, contextSha256)),
1745
+ errorCode: "trusted_session_binding_required", operation: "Memory stage start"
1746
+ }).eventKey;
1747
+ const work = startMemoryStage(context, { projectRoot, runId, stage, bytes: prepared.memoryStage.bytes });
1748
+ try {
1749
+ const binding = bindStageCoordinatorWork(context, { workId: work.work_id, hookEventId: event, stage,
1750
+ promptPath: work.prompt_path, resultPath: work.result_path, ...(contextSha256 ? { contextSha256 } : {}) });
1751
+ // The frozen semantic prompt is also restored by auxiliary owners in
1752
+ // other CLI contexts. Keep native invocation authority in this current
1753
+ // delivery, not in those immutable instruction/custody bytes.
1754
+ const finish = managedLifecycleCommand(context, runtimeCommand(context, ["stage", "finish", runId,
1755
+ "--stage", stage, "--project-root", projectRoot, "--result-file", work.result_path, "--json"]));
1756
+ const pause = stagePauseCommand(context, { projectRoot, runId, stage, workId: work.work_id });
1757
+ const orchestration = memoryStageFanoutDescriptor(context, { projectRoot, runId, stage });
1758
+ const delivery = { ...work, binding, ...(orchestration ? { orchestration } : {}), next: { finish_command: finish, pause_command: pause },
1759
+ 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` };
1760
+ bindLifecyclePublishedPacket(context, delivery.worker_prompt_markdown);
1761
+ return controlLifecycleReply(context, { projectRoot, runId }, delivery);
1762
+ }
1763
+ catch (error) {
1764
+ throw new AppError("memory_stage_binding_pending", "Memory Stage allocated; trusted coordinator binding remains incomplete", 1, { effect: "committed", run_id: runId, stage, work_id: work.work_id, next_action: "reconcile_memory_stage_binding",
1765
+ cause: error instanceof AppError ? error.code : "coordinator_binding_failure" });
1766
+ }
1767
+ }
1758
1768
  const claimVnextStageStart = (runId) => {
1759
1769
  registerProject(context, { root: projectRoot });
1760
1770
  return findRecentMatchingHookEvent(context, {
@@ -1783,7 +1793,7 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
1783
1793
  })
1784
1794
  : claimVnextStageStart(requiredPosition(parsed, 0, "run-id"));
1785
1795
  }
1786
- const result = launchVnextSpecify(context, {
1796
+ const result = sdlcStageHandlers.specify.entry(context, {
1787
1797
  projectRoot,
1788
1798
  ...(prepared.stageStart?.intakeMarkdown !== undefined ? { intakeMarkdown: prepared.stageStart.intakeMarkdown } : externalContext ? { intakeMarkdown: runnerIntake(externalContext) } : intakeFile ? { intakeFile } : { intakeMarkdown: await readStdin(io.stdin) }),
1789
1799
  hookEventId,
@@ -1795,27 +1805,27 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
1795
1805
  }
1796
1806
  if (!bootstrap && stage === "protocolize" && isVnextProtocolizeRun(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id") })) {
1797
1807
  hookEventId ??= claimVnextStageStart(requiredPosition(parsed, 0, "run-id"));
1798
- return attachExternalStageContext(await startVnextProtocolize(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id"), hookEventId, ...(contextSha256 ? { contextSha256 } : {}), ...(externalContext ? { externalContext } : {}) }, prepared.protocolizeStart), externalContext);
1808
+ return attachExternalStageContext(await sdlcStageHandlers.protocolize.entry(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id"), hookEventId, ...(contextSha256 ? { contextSha256 } : {}), ...(externalContext ? { externalContext } : {}) }, prepared.protocolizeStart), externalContext);
1799
1809
  }
1800
1810
  if (!bootstrap && stage === "plan" && isVnextPlanRun(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id") })) {
1801
1811
  hookEventId ??= claimVnextStageStart(requiredPosition(parsed, 0, "run-id"));
1802
- return attachExternalStageContext(startVnextPlan(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id"), hookEventId, ...(contextSha256 ? { contextSha256 } : {}), ...(externalContext ? { externalContext } : {}) }, prepared.planStart), externalContext);
1812
+ return attachExternalStageContext(sdlcStageHandlers.plan.entry(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id"), hookEventId, ...(contextSha256 ? { contextSha256 } : {}), ...(externalContext ? { externalContext } : {}) }, prepared.planStart), externalContext);
1803
1813
  }
1804
1814
  if (!bootstrap && stage === "plan-review" && isVnextPlanReviewRun(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id") })) {
1805
1815
  hookEventId ??= claimVnextStageStart(requiredPosition(parsed, 0, "run-id"));
1806
- return attachExternalStageContext(startVnextPlanReview(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id"), hookEventId, ...(contextSha256 ? { contextSha256 } : {}), ...(externalContext ? { externalContext } : {}) }, prepared.planReviewStart), externalContext);
1816
+ return attachExternalStageContext(sdlcStageHandlers["plan-review"].entry(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id"), hookEventId, ...(contextSha256 ? { contextSha256 } : {}), ...(externalContext ? { externalContext } : {}) }, prepared.planReviewStart), externalContext);
1807
1817
  }
1808
1818
  if (!bootstrap && stage === "code" && isVnextPlanRun(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id") })) {
1809
1819
  hookEventId ??= claimVnextStageStart(requiredPosition(parsed, 0, "run-id"));
1810
- return attachExternalStageContext(await startVnextCode(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id"), hookEventId, progress: commandProgress(io, output), ...(contextSha256 ? { contextSha256 } : {}), ...(externalContext ? { externalContext } : {}) }, prepared.codeStart), externalContext);
1820
+ return attachExternalStageContext(await sdlcStageHandlers.code.entry(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id"), hookEventId, progress: commandProgress(io, output), ...(contextSha256 ? { contextSha256 } : {}), ...(externalContext ? { externalContext } : {}) }, prepared.codeStart), externalContext);
1811
1821
  }
1812
1822
  if (!bootstrap && stage === "code-review" && isVnextCodeReviewRun(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id") })) {
1813
1823
  hookEventId ??= claimVnextStageStart(requiredPosition(parsed, 0, "run-id"));
1814
- return attachExternalStageContext(startVnextCodeReview(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id"), hookEventId, ...(contextSha256 ? { contextSha256 } : {}), ...(externalContext ? { externalContext } : {}) }, prepared.codeReviewStart), externalContext);
1824
+ return attachExternalStageContext(sdlcStageHandlers["code-review"].entry(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id"), hookEventId, ...(contextSha256 ? { contextSha256 } : {}), ...(externalContext ? { externalContext } : {}) }, prepared.codeReviewStart), externalContext);
1815
1825
  }
1816
1826
  if (!bootstrap && stage === "merge" && isVnextMergeRun(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id") })) {
1817
1827
  hookEventId ??= claimVnextStageStart(requiredPosition(parsed, 0, "run-id"));
1818
- return attachExternalStageContext(await startVnextMerge(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id"), hookEventId, progress: commandProgress(io, output), ...(contextSha256 ? { contextSha256 } : {}), ...(externalContext ? { externalContext } : {}) }, prepared.mergeStart), externalContext);
1828
+ return attachExternalStageContext(await sdlcStageHandlers.merge.entry(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id"), hookEventId, progress: commandProgress(io, output), ...(contextSha256 ? { contextSha256 } : {}), ...(externalContext ? { externalContext } : {}) }, prepared.mergeStart), externalContext);
1819
1829
  }
1820
1830
  if (intakeStdin) {
1821
1831
  throw new AppError("usage", "--intake-stdin is only available for vNext SPECIFY", 2);
@@ -1849,6 +1859,17 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
1849
1859
  const hookEventId = optionalOption(parsed, "hook-event-id");
1850
1860
  if (retryCheckId && !retryReason?.trim())
1851
1861
  throw new AppError("usage", "--retry-check requires --reason explaining the recovered environment", 2);
1862
+ if (prepared.memoryStage?.operation === "finish") {
1863
+ // Descriptor settlement validates exact coordinator custody and claims
1864
+ // the fresh hook atomically with result acceptance. Do not consume it
1865
+ // through the SDLC lifecycle owner before that settlement.
1866
+ return controlledReply(finishMemoryStage(context, { projectRoot, runId, stage, bytes: prepared.memoryStage.bytes,
1867
+ hookEventId: hookEventId ?? findRecentMatchingHookEvent(context, {
1868
+ projectId: requireProjectByRoot(context, resolveProjectRoot(projectRoot)).id,
1869
+ matchKey: entityReferenceVariants(runId).map(reference => stageLifecycleMatchKey("stage_finish", reference, stage, projectRoot)),
1870
+ errorCode: "trusted_session_binding_required", operation: "Memory stage finish"
1871
+ }).eventKey }));
1872
+ }
1852
1873
  const protectedLifecycle = (stage === "specify" && isVnextSpecifyRun(context, { projectRoot, runId }))
1853
1874
  || (stage === "protocolize" && isVnextProtocolizeRun(context, { projectRoot, runId }))
1854
1875
  || (stage === "plan" && isVnextPlanRun(context, { projectRoot, runId }))
@@ -1868,7 +1889,7 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
1868
1889
  if (!resultFile && !resultStdin) {
1869
1890
  throw new AppError("usage", "vNext SPECIFY finish requires --result-file or --result-stdin", 2);
1870
1891
  }
1871
- return controlledReply(await finishVnextSpecifyStage(context, {
1892
+ return controlledReply(await sdlcStageHandlers.specify.finish(context, {
1872
1893
  projectRoot,
1873
1894
  runId,
1874
1895
  ...(resultFile ? { resultFile } : prepared.stageFinish?.value ? {} : { resultJson: await readStdin(io.stdin) }),
@@ -1880,34 +1901,34 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
1880
1901
  if (!resultFile || resultStdin || hasOption(parsed, "outcome")) {
1881
1902
  throw new AppError("usage", "vNext PROTOCOLIZE requires exactly --result-file", 2);
1882
1903
  }
1883
- return controlledReply(await finishVnextProtocolize(context, { projectRoot, runId, resultFile, ...(prepared.stageFinish?.value ? { result: prepared.stageFinish.value } : {}) }));
1904
+ return controlledReply(await sdlcStageHandlers.protocolize.finish(context, { projectRoot, runId, resultFile, ...(prepared.stageFinish?.value ? { result: prepared.stageFinish.value } : {}) }));
1884
1905
  }
1885
1906
  if (stage === "plan" && isVnextPlanRun(context, { projectRoot, runId })) {
1886
1907
  if (optionalOption(parsed, "code-work-batch-file"))
1887
1908
  throw new AppError("usage", "vNext PLAN derives its CODE batch from accepted semantic plans; do not supply a batch file", 2);
1888
- return controlledReply(await finishVnextPlan(context, { projectRoot, runId, ...(prepared.planFinish ? { prepared: prepared.planFinish } : {}) }));
1909
+ return controlledReply(await sdlcStageHandlers.plan.finish(context, { projectRoot, runId, ...(prepared.planFinish ? { prepared: prepared.planFinish } : {}) }));
1889
1910
  }
1890
1911
  if (stage === "plan-review" && isVnextPlanReviewRun(context, { projectRoot, runId })) {
1891
1912
  if (resultStdin || hasOption(parsed, "outcome"))
1892
1913
  throw new AppError("usage", "vNext PLAN-REVIEW uses --decision-file", 2);
1893
1914
  const decisionFile = optionalOption(parsed, "decision-file");
1894
- return controlledReply(await finishVnextPlanReview(context, { projectRoot, runId, ...(decisionFile ? { decisionFile } : {}), ...(prepared.stageFinish?.value ? { decision: prepared.stageFinish.value, decisionText: prepared.stageFinish.text } : {}) }));
1915
+ return controlledReply(await sdlcStageHandlers["plan-review"].finish(context, { projectRoot, runId, ...(decisionFile ? { decisionFile } : {}), ...(prepared.stageFinish?.value ? { decision: prepared.stageFinish.value, decisionText: prepared.stageFinish.text } : {}) }));
1895
1916
  }
1896
1917
  if (stage === "code" && isVnextPlanRun(context, { projectRoot, runId })) {
1897
1918
  if (semanticFile || resultFile || resultStdin || hasOption(parsed, "outcome")) {
1898
1919
  throw new AppError("usage", "vNext CODE finish accepts only --verification-file", 2);
1899
1920
  }
1900
- return controlledReply(await finishVnextCode(context, { projectRoot, runId, verificationFile: optionalOption(parsed, "verification-file") ?? path.join("<missing>", "code-verification.json"), ...(prepared.stageFinish?.value ? { verification: prepared.stageFinish.value } : {}), ...(retryCheckId ? { retryCheckId, retryReason: retryReason } : {}), progress: commandProgress(io, output) }));
1921
+ return controlledReply(await sdlcStageHandlers.code.finish(context, { projectRoot, runId, verificationFile: optionalOption(parsed, "verification-file") ?? path.join("<missing>", "code-verification.json"), ...(prepared.stageFinish?.value ? { verification: prepared.stageFinish.value } : {}), ...(retryCheckId ? { retryCheckId, retryReason: retryReason } : {}), progress: commandProgress(io, output) }));
1901
1922
  }
1902
1923
  if (stage === "code-review" && isVnextCodeReviewRun(context, { projectRoot, runId })) {
1903
1924
  if (resultStdin || semanticFile || resultFile || hasOption(parsed, "outcome"))
1904
1925
  throw new AppError("usage", "vNext CODE-REVIEW uses --decision-file", 2);
1905
- return controlledReply(await finishVnextCodeReview(context, { projectRoot, runId, ...(optionalOption(parsed, "decision-file") ? { decisionFile: optionalOption(parsed, "decision-file") } : {}), ...(prepared.stageFinish?.value ? { decision: prepared.stageFinish.value, decisionText: prepared.stageFinish.text } : {}), ...(retryCheckId ? { retryCheckId, retryReason: retryReason } : {}), progress: commandProgress(io, output) }));
1926
+ return controlledReply(await sdlcStageHandlers["code-review"].finish(context, { projectRoot, runId, ...(optionalOption(parsed, "decision-file") ? { decisionFile: optionalOption(parsed, "decision-file") } : {}), ...(prepared.stageFinish?.value ? { decision: prepared.stageFinish.value, decisionText: prepared.stageFinish.text } : {}), ...(retryCheckId ? { retryCheckId, retryReason: retryReason } : {}), progress: commandProgress(io, output) }));
1906
1927
  }
1907
1928
  if (stage === "merge" && isVnextMergeRun(context, { projectRoot, runId })) {
1908
1929
  if (resultStdin || semanticFile || resultFile || hasOption(parsed, "outcome"))
1909
1930
  throw new AppError("usage", "vNext MERGE uses the Work result path returned by stage start", 2);
1910
- return controlledReply(await finishVnextMerge(context, { projectRoot, runId, requestId: requiredOption(parsed, "request"), workId: requiredOption(parsed, "work"), ...(retryCheckId ? { retryCheckId, retryReason: retryReason } : {}), progress: commandProgress(io, output) }, prepared.mergeFinish));
1931
+ return controlledReply(await sdlcStageHandlers.merge.finish(context, { projectRoot, runId, requestId: requiredOption(parsed, "request"), workId: requiredOption(parsed, "work"), ...(retryCheckId ? { retryCheckId, retryReason: retryReason } : {}), progress: commandProgress(io, output) }, prepared.mergeFinish));
1911
1932
  }
1912
1933
  if (hasOption(parsed, "outcome") || hasOption(parsed, "result-file") || resultStdin) {
1913
1934
  throw new AppError("usage", "--outcome, --result-file and --result-stdin are only available for vNext SPECIFY", 2);
@@ -2055,7 +2076,7 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
2055
2076
  return prepared.schemaValidation;
2056
2077
  }
2057
2078
  if (family === "memory") {
2058
- return dispatchMemory(command, parsed);
2079
+ return dispatchMemory(context, command, parsed, prepared);
2059
2080
  }
2060
2081
  if (family === "migration") {
2061
2082
  return dispatchMigration(context, command, parsed, classification, prepared);
@@ -2368,7 +2389,7 @@ function dispatchMergeWorker(context, command, parsed) {
2368
2389
  }
2369
2390
  throw new AppError("usage", `Unknown merge-worker command: ${command ?? "<empty>"}`, 2);
2370
2391
  }
2371
- function dispatchMemory(command, parsed) {
2392
+ function dispatchMemory(context, command, parsed, prepared) {
2372
2393
  const subcommand = requiredPosition(parsed, 0, "memory subcommand");
2373
2394
  if (command === "permissions" && subcommand === "preflight") {
2374
2395
  return preflightMemoryPermissions({
@@ -2379,6 +2400,103 @@ function dispatchMemory(command, parsed) {
2379
2400
  mode: requiredOption(parsed, "mode")
2380
2401
  });
2381
2402
  }
2403
+ const scope = () => {
2404
+ const projectRoot = requiredOption(parsed, "project-root");
2405
+ const project = requireProjectByRoot(context, resolveProjectRoot(projectRoot));
2406
+ return { projectRoot, runId: resolveRun(context, project.id, requiredOption(parsed, "run")).id };
2407
+ };
2408
+ if (command === "repair") {
2409
+ const wave = requiredOption(parsed, "wave");
2410
+ if (wave !== "1" && wave !== "2")
2411
+ throw new AppError("usage", "Memory repairs support only waves 1 and 2", 2);
2412
+ const work = { ...scope(), workId: requiredOption(parsed, "work") };
2413
+ if (subcommand === "baseline")
2414
+ return (wave === "1" ? registerMemoryRepairBaselineFromStage : registerMemorySecondRepairBaselineFromStage)(context, work);
2415
+ if (subcommand === "copy-reserve")
2416
+ return (wave === "1" ? reserveMemoryRepairWriterCopyFromStage : reserveMemorySecondRepairCopyFromStage)(context, work);
2417
+ if (subcommand === "copy-materialize")
2418
+ return (wave === "1" ? materializeMemoryRepairWriterCopyFromStage : materializeMemorySecondRepairCopyFromStage)(context, work);
2419
+ if (subcommand === "copy-dispatch")
2420
+ return (wave === "1" ? prepareMemoryRepairDispatchFromStage : prepareMemorySecondRepairDispatchFromStage)(context, work);
2421
+ const workspaceRoot = requiredOption(parsed, "workspace-root");
2422
+ if (wave === "2") {
2423
+ const bundle = readFlowRunExecutionBundle(context, work);
2424
+ if (!bundle || bundle.descriptor.descriptor.id !== "mb-init" || bundle.execution.snapshot().scope.workspace !== workspaceRoot)
2425
+ throw new AppError("memory_repair_scope_invalid", "Repair workspace does not match its frozen memory RUN", 2, { phase: "prepare", effect: "no_effect" });
2426
+ }
2427
+ if (subcommand === "current-view")
2428
+ return wave === "1"
2429
+ ? registerMemoryRepairCurrentViewFromStage(context, { ...work, workspaceRoot })
2430
+ : registerMemorySecondRepairCurrentViewFromStage(context, work);
2431
+ const output = { ...work, workspaceRoot, workSessionId: requiredOption(parsed, "work-session") };
2432
+ if (subcommand === "publication-source" && wave === "1")
2433
+ return registerMemoryRepairPublicationSourceFromStage(context, output);
2434
+ if (subcommand === "publication-reserve") {
2435
+ if (!prepared.memoryOperationBytes)
2436
+ throw new AppError("cli_input_unprepared", "Memory repair output bytes were not prepared", 1);
2437
+ return (wave === "1" ? reserveMemoryRepairPublicationAgainstSourceFromStage : reserveMemorySecondRepairPublicationFromStage)(context, { ...output, bytes: prepared.memoryOperationBytes });
2438
+ }
2439
+ if (subcommand === "publication-apply")
2440
+ return (wave === "1" ? applyMemoryRepairPublicationFromStage : applyMemorySecondRepairPublicationFromStage)(context, output);
2441
+ if (subcommand === "publication-finish")
2442
+ return (wave === "1" ? finishMemoryRepairPublicationFromStage : finishMemorySecondRepairPublicationFromStage)(context, output);
2443
+ }
2444
+ if (command === "compose" && subcommand === "register") {
2445
+ if (!prepared.memoryOperationBytes)
2446
+ throw new AppError("cli_input_unprepared", "Memory composition bytes were not prepared", 1);
2447
+ try {
2448
+ return registerMemoryCompositionFromStage(context, { ...scope(), requestKey: requiredOption(parsed, "request-key"), bytes: prepared.memoryOperationBytes });
2449
+ }
2450
+ catch (error) {
2451
+ if (error instanceof AppError && (error.code === "memory_stage_result_invalid"
2452
+ || error.code === "memory_preflight_handler_invalid" && ["unselected_preflight_source", "proposed_source_sha256_mismatch"].includes(String(error.details.reason))) && error.details.phase === "prepare"
2453
+ && error.details.effect === "no_effect" && error.details.recoverable === true) {
2454
+ error.details.retry_command = runtimeCommand(context, ["memory", "compose", "register", "--run", requiredOption(parsed, "run"),
2455
+ "--project-root", requiredOption(parsed, "project-root"), "--request-key", requiredOption(parsed, "request-key"),
2456
+ "--result-file", requiredOption(parsed, "result-file"), "--json", "--progress-jsonl"]);
2457
+ error.details.retry_instruction = "Correct only the rejected composition proposal, then execute retry_command in this same Session. No Work graph was registered by this rejected call; do not dispatch children or finish the Stage until registration succeeds.";
2458
+ }
2459
+ throw error;
2460
+ }
2461
+ }
2462
+ if (command === "verify" && subcommand === "checks")
2463
+ return runMemoryVerificationChecks(context, scope());
2464
+ if (command === "review" && subcommand === "register")
2465
+ return registerMemoryReviewFromStage(context, scope());
2466
+ if (command === "review" && subcommand === "collect") {
2467
+ const wave = collectMemoryInitialReviewFromStage(context, scope());
2468
+ const selected = scope(), bundle = readFlowRunExecutionBundle(context, selected);
2469
+ if (!bundle)
2470
+ throw new AppError("memory_review_handler_invalid", "Registered Memory bundle required", 2);
2471
+ const project = requireProjectByRoot(context, resolveProjectRoot(selected.projectRoot));
2472
+ const retained = PreparedRetainedMemoryReviewResults.prepare(context, PreparedRetainedMemoryReviewAuthority.prepare(context, { projectId: project.id, runId: selected.runId }, bundle));
2473
+ return { references: wave.references(), projection: wave.resultProjection(),
2474
+ correction_plan_binding: { schema_id: "dd-flow/memory-review-correction-plan@1", run_id: selected.runId, wave: 1, review_sha256: retained.sha256 } };
2475
+ }
2476
+ if (command === "finish" && subcommand === "evidence")
2477
+ return registerMemoryFinishEvidenceFromStage(context, scope());
2478
+ if (command === "finish" && subcommand === "integrate")
2479
+ return integrateMemoryFinishFromStage(context, scope());
2480
+ if (command === "corrections" || command === "review" && ["selective-register", "selective-collect"].includes(subcommand)) {
2481
+ const wave = requiredOption(parsed, "wave");
2482
+ if (wave !== "1" && wave !== "2")
2483
+ throw new AppError("usage", "Memory corrections support only waves 1 and 2", 2);
2484
+ if (command === "corrections" && subcommand === "register") {
2485
+ if (!prepared.memoryOperationBytes)
2486
+ throw new AppError("cli_input_unprepared", "Memory correction plan bytes were not prepared", 1);
2487
+ const register = wave === "1" ? registerMemoryCorrectionsFromStage : registerMemorySecondCorrectionsFromStage;
2488
+ return register(context, { ...scope(), bytes: prepared.memoryOperationBytes });
2489
+ }
2490
+ if (command === "corrections" && subcommand === "checks")
2491
+ return (wave === "1" ? runMemoryCorrectionChecksFromStage : runMemorySecondCorrectionChecksFromStage)(context, scope());
2492
+ if (command === "review" && subcommand === "selective-register")
2493
+ return (wave === "1" ? registerCorrectedMemoryReviewFromStage : registerSecondCorrectedMemoryReviewFromStage)(context, scope());
2494
+ if (command === "review" && subcommand === "selective-collect") {
2495
+ const accepted = (wave === "1" ? collectCorrectedMemoryReviewFromStage : collectSecondCorrectedMemoryReviewFromStage)(context, scope());
2496
+ return { wave: Number(wave), references: accepted.references(), projection: accepted.resultProjection(),
2497
+ ...(wave === "1" ? { correction_plan_binding: { schema_id: "dd-flow/memory-review-correction-plan@1", run_id: scope().runId, wave: 2, review_sha256: accepted.sha256 } } : {}) };
2498
+ }
2499
+ }
2382
2500
  throw new AppError("usage", `Unknown memory command: ${["memory", command, subcommand].filter(Boolean).join(" ")}`, 2);
2383
2501
  }
2384
2502
  function completedCommandExitCode(payload) {
@@ -2504,7 +2622,8 @@ function dispatchRun(context, command, parsed, prepared = {}) {
2504
2622
  if (bootstrapAction === "create")
2505
2623
  return createEvalBootstrapSnapshot(context, {
2506
2624
  projectRoot: requiredOption(parsed, "project-root"),
2507
- output: requiredOption(parsed, "output")
2625
+ output: requiredOption(parsed, "output"),
2626
+ flow: optionalOption(parsed, "flow")
2508
2627
  });
2509
2628
  if (bootstrapAction === "restore")
2510
2629
  return restoreEvalBootstrapSnapshot(context, snapshotRestoreInput(parsed), prepared.bootstrapRestore);
@@ -2600,7 +2719,8 @@ function dispatchRun(context, command, parsed, prepared = {}) {
2600
2719
  return attachFlowRunStage(context, stageAttachmentInput(parsed));
2601
2720
  }
2602
2721
  if (command === "complete-stage") {
2603
- return completeFlowRunStage(context, stageCompletionInput(parsed));
2722
+ const input = stageCompletionInput(parsed);
2723
+ return completeFlowRunStage(context, input, prepareRawFlowRunStageCompletion(context, input));
2604
2724
  }
2605
2725
  if (command === "complete") {
2606
2726
  throw new AppError("usage", "run complete is retired; only an operator may use run override", 2);
@@ -3184,7 +3304,7 @@ function parseArgs(args) {
3184
3304
  function requiredPosition(parsed, index, label) {
3185
3305
  const value = parsed.positional[index];
3186
3306
  if (!value) {
3187
- throw new AppError("usage", `Missing required argument: ${label}`, 2);
3307
+ throw new AppError("usage", `Missing required argument: ${label}`, 2, { parameter: label, reason: "missing_required_argument" });
3188
3308
  }
3189
3309
  return value;
3190
3310
  }
@@ -3194,7 +3314,7 @@ function allOptions(parsed, key) {
3194
3314
  function requiredScopeProjectRoot(root, operation) {
3195
3315
  if (root)
3196
3316
  return root;
3197
- throw new AppError("usage", `${operation} requires --project-root or a unique protocol context`, 2);
3317
+ throw new AppError("usage", `${operation} requires --project-root or a unique protocol context`, 2, { parameter: "project-root", reason: "missing_required_option" });
3198
3318
  }
3199
3319
  function requiredOptionOrScope(parsed, root, key) {
3200
3320
  return root ?? requiredOption(parsed, key);
@@ -3213,7 +3333,7 @@ function requiredOptionAlias(parsed, keys) {
3213
3333
  if (value)
3214
3334
  return value;
3215
3335
  }
3216
- throw new AppError("usage", `Missing required option: ${keys.map((key) => `--${key}`).join(" or ")}`, 2);
3336
+ throw new AppError("usage", `Missing required option: ${keys.map((key) => `--${key}`).join(" or ")}`, 2, { parameter: [...keys].sort(), reason: "missing_required_option" });
3217
3337
  }
3218
3338
  function hasOption(parsed, key) {
3219
3339
  return parsed.options.has(key);
@@ -3243,11 +3363,13 @@ function parseWorktreePolicy(value) {
3243
3363
  }
3244
3364
  throw new AppError("validation", "--worktree must be keep or remove", 2);
3245
3365
  }
3246
- async function readStdin(stream) {
3366
+ async function readStdin(stream, maxBytes) {
3247
3367
  if (!stream) {
3248
3368
  return "";
3249
3369
  }
3250
3370
  let data = "";
3371
+ if (maxBytes !== undefined)
3372
+ return readBoundedUtf8Stream(stream, maxBytes);
3251
3373
  stream.setEncoding("utf8");
3252
3374
  for await (const chunk of stream) {
3253
3375
  data += chunk;
@@ -3263,7 +3385,8 @@ function refreshDashboardsAfterMutation(context, args, result, resolvedScope) {
3263
3385
  const projectRoot = projectRootForMutation(context, args, result, resolvedScope);
3264
3386
  if (!projectRoot)
3265
3387
  return [];
3266
- autoRefreshDashboards(context, { projectRoot });
3388
+ const runId = result && typeof result === "object" && "run_id" in result && typeof result.run_id === "string" ? result.run_id : undefined;
3389
+ autoRefreshDashboards(context, { projectRoot, ...(runId ? { runId } : {}) });
3267
3390
  return [];
3268
3391
  }
3269
3392
  catch (error) {