@deksden-com/dd-flow-cli 0.9.0-beta.137 → 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 (260) hide show
  1. package/CHANGELOG.md +4 -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 +197 -0
  7. package/dist/cli/command-option-descriptions.js +191 -0
  8. package/dist/cli/completion-cli.js +70 -0
  9. package/dist/cli/completion.js +57 -0
  10. package/dist/cli/error-output.js +52 -0
  11. package/dist/cli/executor-onboarding.js +76 -0
  12. package/dist/cli/flows.js +29 -0
  13. package/dist/cli/harnesses.js +84 -0
  14. package/dist/cli/help.js +240 -6
  15. package/dist/cli/input-preparation.js +54 -5
  16. package/dist/cli/memory-flow-admission.js +44 -0
  17. package/dist/cli/memory-init-invocation.js +78 -0
  18. package/dist/cli/memory-init.js +240 -0
  19. package/dist/cli/memory-storage-admission.js +53 -0
  20. package/dist/cli/models.js +39 -0
  21. package/dist/cli/native-hook-ingress.js +1 -1
  22. package/dist/cli/operator-profiles.js +61 -0
  23. package/dist/cli/output-options.js +35 -0
  24. package/dist/cli/response-file.js +71 -0
  25. package/dist/cli/run-cli.js +283 -160
  26. package/dist/cli/setup.js +149 -0
  27. package/dist/cli.js +54 -2
  28. package/dist/domain/stage-handler-identities.js +20 -0
  29. package/dist/harness-runtime/lib/daemon-operations.d.mts +1 -0
  30. package/dist/harness-runtime/lib/daemon-operations.mjs +4 -3
  31. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +4 -2
  32. package/dist/harness-runtime/lib/dd-codex-daemon.mjs +11 -5
  33. package/dist/harness-runtime/lib/dd-codex.mjs +22 -10
  34. package/dist/harness-runtime/lib/dd-droid-daemon.mjs +2 -1
  35. package/dist/harness-runtime/lib/dd-droid.mjs +2 -1
  36. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +4 -2
  37. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +6 -4
  38. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +9 -9
  39. package/dist/harness-runtime/lib/delegation-instructions.mjs +5 -3
  40. package/dist/harness-runtime/lib/lifecycle-command.mjs +1 -0
  41. package/dist/harness-runtime/lib/managed-daemon.d.mts +1 -0
  42. package/dist/harness-runtime/lib/managed-daemon.mjs +50 -15
  43. package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
  44. package/dist/harness-runtime/lib/native-hook-command.mjs +1 -1
  45. package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
  46. package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
  47. package/dist/harness-runtime/lib/opencode-plugin.mjs +2 -0
  48. package/dist/harness-runtime/lib/operation-progress.mjs +3 -1
  49. package/dist/runtime/context.js +1 -1
  50. package/dist/schemas/discovery-result.schema.json +184 -0
  51. package/dist/schemas/execution-bundle.schema.json +205 -0
  52. package/dist/schemas/execution-settings.schema.json +162 -0
  53. package/dist/schemas/flow-descriptor.schema.json +54 -0
  54. package/dist/schemas/flow-run.schema.json +22 -0
  55. package/dist/schemas/harness-catalog.schema.json +80 -0
  56. package/dist/schemas/mb-init-compose-result.schema.json +457 -0
  57. package/dist/schemas/mb-init-discover-result.schema.json +500 -0
  58. package/dist/schemas/mb-init-finish-result.schema.json +422 -0
  59. package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
  60. package/dist/schemas/mb-init-review-result.schema.json +396 -0
  61. package/dist/schemas/mb-init-verify-result.schema.json +391 -0
  62. package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
  63. package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
  64. package/dist/schemas/memory-composition-work-result.schema.json +38 -0
  65. package/dist/schemas/memory-repair-work-result.schema.json +49 -0
  66. package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
  67. package/dist/schemas/memory-review-work-result.schema.json +43 -0
  68. package/dist/schemas/model-catalog.schema.json +153 -0
  69. package/dist/schemas/profile-settings.schema.json +122 -0
  70. package/dist/schemas/release-manifest.schema.json +291 -0
  71. package/dist/schemas/run-engine-binding.schema.json +1 -1
  72. package/dist/services/check-runner-evidence.js +51 -4
  73. package/dist/services/cli-operation-classifier.js +8 -47
  74. package/dist/services/cli-upgrade-allowlist.js +27 -0
  75. package/dist/services/code-checks.js +387 -34
  76. package/dist/services/controller-execution.js +88 -0
  77. package/dist/services/controller-fanout.js +71 -12
  78. package/dist/services/dashboard.js +8 -2
  79. package/dist/services/descriptor-coordinator-session.js +35 -0
  80. package/dist/services/descriptor-root-work.js +53 -0
  81. package/dist/services/descriptor-run-settlement.js +105 -0
  82. package/dist/services/descriptor-run-start.js +449 -0
  83. package/dist/services/descriptor-stage-coordinator.js +197 -0
  84. package/dist/services/descriptor-stage-settlement.js +222 -0
  85. package/dist/services/descriptor-stage-start.js +139 -0
  86. package/dist/services/discovery/agy-discovery.js +2 -0
  87. package/dist/services/discovery/codex-discovery.js +2 -0
  88. package/dist/services/discovery/droid-discovery.js +2 -0
  89. package/dist/services/discovery/grok-discovery.js +2 -0
  90. package/dist/services/discovery/opencode-discovery.js +2 -0
  91. package/dist/services/discovery/static.js +31 -0
  92. package/dist/services/discovery/zcode-discovery.js +2 -0
  93. package/dist/services/engines.js +39 -22
  94. package/dist/services/eval-snapshots.js +83 -25
  95. package/dist/services/execution-bundles.js +263 -0
  96. package/dist/services/execution-policy.js +20 -16
  97. package/dist/services/executor-onboarding.js +56 -0
  98. package/dist/services/external-work-launch.js +91 -11
  99. package/dist/services/flow-catalog.js +21 -0
  100. package/dist/services/flow-descriptors.js +82 -0
  101. package/dist/services/frozen-engine.js +242 -0
  102. package/dist/services/generic-execution.js +164 -0
  103. package/dist/services/harness-adapter.js +28 -2
  104. package/dist/services/harness-discovery.js +29 -0
  105. package/dist/services/harness-doctor.js +75 -0
  106. package/dist/services/harness-probe-effects.js +51 -0
  107. package/dist/services/harness-version-probe.js +100 -0
  108. package/dist/services/hooks.js +24 -6
  109. package/dist/services/hybrid-contracts.js +483 -0
  110. package/dist/services/ids.js +29 -1
  111. package/dist/services/installation-lock.js +95 -0
  112. package/dist/services/installed-flow-source.js +183 -0
  113. package/dist/services/lifecycle-invocations.js +257 -78
  114. package/dist/services/memory-accepted-composition.js +77 -0
  115. package/dist/services/memory-baseline-preservation.js +65 -0
  116. package/dist/services/memory-completed-correction-wave.js +320 -0
  117. package/dist/services/memory-compose-handler.js +258 -0
  118. package/dist/services/memory-composition-acceptance.js +199 -0
  119. package/dist/services/memory-composition-graph.js +134 -0
  120. package/dist/services/memory-composition-registration.js +146 -0
  121. package/dist/services/memory-composition-work-custody.js +151 -0
  122. package/dist/services/memory-composition-work-results.js +96 -0
  123. package/dist/services/memory-corrected-review-acceptance.js +129 -0
  124. package/dist/services/memory-corrected-review-batch.js +30 -0
  125. package/dist/services/memory-corrected-review-findings.js +106 -0
  126. package/dist/services/memory-corrected-review-inputs.js +210 -0
  127. package/dist/services/memory-corrected-review-projection.js +78 -0
  128. package/dist/services/memory-corrected-review-receipt.js +170 -0
  129. package/dist/services/memory-corrected-review-registration.js +191 -0
  130. package/dist/services/memory-correction-check-receipt.js +219 -0
  131. package/dist/services/memory-correction-input-owner.js +6 -0
  132. package/dist/services/memory-discover-handler.js +104 -0
  133. package/dist/services/memory-finish-evidence.js +435 -0
  134. package/dist/services/memory-finish-handler.js +215 -0
  135. package/dist/services/memory-finish-integration.js +280 -0
  136. package/dist/services/memory-finish-readiness.js +122 -0
  137. package/dist/services/memory-git-integration.js +151 -0
  138. package/dist/services/memory-historical-corrected-review.js +206 -0
  139. package/dist/services/memory-historical-original-review.js +130 -0
  140. package/dist/services/memory-historical-repair-registration.js +99 -0
  141. package/dist/services/memory-historical-second-review.js +128 -0
  142. package/dist/services/memory-init-bootstrap-readiness.js +210 -0
  143. package/dist/services/memory-init-contexts.js +89 -0
  144. package/dist/services/memory-init-controller-start.js +84 -0
  145. package/dist/services/memory-init-engine-release.js +223 -0
  146. package/dist/services/memory-init-git-policy.js +136 -0
  147. package/dist/services/memory-init-lint-capability.js +185 -0
  148. package/dist/services/memory-init-native-capacity.js +241 -0
  149. package/dist/services/memory-init-preflight.js +312 -0
  150. package/dist/services/memory-init-project-bootstrap.js +599 -0
  151. package/dist/services/memory-init-request-candidate.js +157 -0
  152. package/dist/services/memory-init-request-input.js +66 -0
  153. package/dist/services/memory-init-resource-storage.js +125 -0
  154. package/dist/services/memory-init-run-allocation.js +81 -0
  155. package/dist/services/memory-init-run-bundle.js +98 -0
  156. package/dist/services/memory-init-start.js +175 -0
  157. package/dist/services/memory-init-startup-custody.js +80 -0
  158. package/dist/services/memory-init-startup-input.js +240 -0
  159. package/dist/services/memory-init-storage.js +81 -0
  160. package/dist/services/memory-init-stores.js +359 -0
  161. package/dist/services/memory-init-worktrunk-capability.js +172 -0
  162. package/dist/services/memory-layer-publication.js +611 -0
  163. package/dist/services/memory-layer.js +156 -0
  164. package/dist/services/memory-lint-config.js +85 -0
  165. package/dist/services/memory-native-review-copy.js +165 -0
  166. package/dist/services/memory-normal-flow-entry.js +75 -0
  167. package/dist/services/memory-ordinary-defaults.js +112 -0
  168. package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
  169. package/dist/services/memory-preflight-handler.js +259 -0
  170. package/dist/services/memory-repair-current-view.js +299 -0
  171. package/dist/services/memory-repair-document-delta.js +451 -0
  172. package/dist/services/memory-repair-history.js +491 -0
  173. package/dist/services/memory-repair-physical-binding.js +312 -0
  174. package/dist/services/memory-repair-publication-files.js +152 -0
  175. package/dist/services/memory-repair-publication-intent.js +27 -0
  176. package/dist/services/memory-repair-publication-plan.js +160 -0
  177. package/dist/services/memory-repair-publication-source.js +225 -0
  178. package/dist/services/memory-repair-publication.js +794 -0
  179. package/dist/services/memory-repair-registration.js +239 -0
  180. package/dist/services/memory-repair-work-baseline.js +413 -0
  181. package/dist/services/memory-repair-work-completion.js +97 -0
  182. package/dist/services/memory-repair-work-custody.js +73 -0
  183. package/dist/services/memory-repair-work-results.js +89 -0
  184. package/dist/services/memory-repair-workspace.js +252 -0
  185. package/dist/services/memory-repair-writer-copy.js +735 -0
  186. package/dist/services/memory-result-binding.js +173 -0
  187. package/dist/services/memory-retained-review-authority.js +129 -0
  188. package/dist/services/memory-retained-review-results.js +70 -0
  189. package/dist/services/memory-retained-second-baseline.js +102 -0
  190. package/dist/services/memory-retained-second-repairs.js +156 -0
  191. package/dist/services/memory-review-acceptance.js +214 -0
  192. package/dist/services/memory-review-correction-plan.js +171 -0
  193. package/dist/services/memory-review-handler.js +585 -0
  194. package/dist/services/memory-review-inputs.js +200 -0
  195. package/dist/services/memory-review-receipt.js +180 -0
  196. package/dist/services/memory-review-registration.js +108 -0
  197. package/dist/services/memory-review-work-custody.js +124 -0
  198. package/dist/services/memory-review-work-input.js +72 -0
  199. package/dist/services/memory-review-work-results.js +73 -0
  200. package/dist/services/memory-second-corrected-review-inputs.js +165 -0
  201. package/dist/services/memory-second-correction-plan.js +76 -0
  202. package/dist/services/memory-second-repair-baseline.js +91 -0
  203. package/dist/services/memory-second-repair-launch.js +614 -0
  204. package/dist/services/memory-second-repair-registration.js +88 -0
  205. package/dist/services/memory-second-repair-source.js +187 -0
  206. package/dist/services/memory-second-review-acceptance.js +115 -0
  207. package/dist/services/memory-source-observations.js +117 -0
  208. package/dist/services/memory-stage-dispatch.js +28 -0
  209. package/dist/services/memory-stage-results.js +199 -0
  210. package/dist/services/memory-verification-acceptance.js +135 -0
  211. package/dist/services/memory-verification-checks.js +252 -0
  212. package/dist/services/memory-verification-receipt.js +159 -0
  213. package/dist/services/memory-verify-handler.js +135 -0
  214. package/dist/services/memory-work-result-preparation.js +63 -0
  215. package/dist/services/model-catalog.js +109 -0
  216. package/dist/services/model-discovery.js +46 -0
  217. package/dist/services/operator-profiles.js +236 -0
  218. package/dist/services/projects.js +17 -2
  219. package/dist/services/recovery-snapshot-database.js +416 -1
  220. package/dist/services/release-archive-producer.js +52 -0
  221. package/dist/services/release-archive.js +143 -0
  222. package/dist/services/release-cache.js +142 -0
  223. package/dist/services/release-compatibility.js +18 -0
  224. package/dist/services/release-download.js +67 -0
  225. package/dist/services/release-envelope.js +104 -0
  226. package/dist/services/release-manifest.js +45 -0
  227. package/dist/services/release-payload.js +114 -0
  228. package/dist/services/release-producer.js +63 -0
  229. package/dist/services/release-provenance.js +160 -0
  230. package/dist/services/release-registry.js +66 -0
  231. package/dist/services/release-source.js +194 -0
  232. package/dist/services/repair-intents.js +1 -1
  233. package/dist/services/review-copy.js +10 -2
  234. package/dist/services/run-control.js +80 -9
  235. package/dist/services/run-controller-capture.js +10 -3
  236. package/dist/services/run-controller-process.js +21 -0
  237. package/dist/services/run-controller-recovery.js +3 -1
  238. package/dist/services/run-controller-state.js +1 -1
  239. package/dist/services/run-controller.js +101 -40
  240. package/dist/services/run-recovery-guard.js +2 -0
  241. package/dist/services/run-recovery.js +145 -5
  242. package/dist/services/run-start-custody.js +177 -0
  243. package/dist/services/runs.js +319 -25
  244. package/dist/services/setup.js +377 -0
  245. package/dist/services/stage-context.js +9 -1
  246. package/dist/services/stage-handlers.js +74 -0
  247. package/dist/services/stage-report-renderer.js +63 -0
  248. package/dist/services/stage-work-graph.js +17 -0
  249. package/dist/services/vnext-code.js +3 -3
  250. package/dist/services/vnext-execution-profile.js +2 -2
  251. package/dist/services/vnext-fanout.js +70 -9
  252. package/dist/services/vnext-merge.js +8 -3
  253. package/dist/services/vnext-plan-review.js +6 -4
  254. package/dist/services/work-registry.js +616 -71
  255. package/dist/services/workspace-files.js +1 -1
  256. package/dist/storage/database.js +84 -6
  257. package/dist/storage/writer-contract.js +11 -7
  258. package/package.json +13 -3
  259. package/tools/create-canon-release.mjs +33 -0
  260. package/tools/produce-hybrid-release.mjs +41 -0
package/dist/cli/help.js CHANGED
@@ -1,4 +1,171 @@
1
+ import { AppError } from "../shared/errors.js";
2
+ import { commandInputs, commandAliases } from "./command-inputs.js";
3
+ import { commandKeyForPositions, globalOptionDocumentation, optionsForCommandTree, routerNativeRoute } from "./command-metadata.js";
1
4
  const helpPages = new Map([
5
+ ["flow mb-init", `dd-flow init / flow mb-init - managed project Memory Bank initialization
6
+
7
+ Usage:
8
+ dd-flow init --project-root /absolute/project --workspace-root /absolute/workspace --request-id ID --intake-file /absolute/intake.txt --intake-sha256 SHA256 --git-route integration_branch_direct --integration-branch main [--profile ID-or-alias] [--detach] --json
9
+ dd-flow flow mb-init --project-root /absolute/project --workspace-root /absolute/workspace --request-id ID [--detach] --json
10
+
11
+ Both spellings share one command definition and dispatcher. Fresh execution
12
+ requires the original bounded UTF-8 intake bytes and explicit Git policy.
13
+ setup installs the computer-level canon; init initializes the specified project.
14
+ Missing executor defaults or prerequisites refuse before project publication.
15
+ Profiles, descriptor, engine and original request are frozen before dispatch.
16
+
17
+ Replay uses the exact retained request, not current defaults, aliases or canon.
18
+ Omitted selectors reuse original choices; supplied selectors must match them.
19
+ The original intake file need not survive replay: its supplied hash must match
20
+ the retained bytes. --stage-profile stage=profile and --work-profile profile
21
+ are repeatable approved overrides, frozen before launch.
22
+
23
+ --profile-file /absolute/profile.json is exclusive with --profile and supplies
24
+ one complete validated operation-only profile. It never saves a global profile
25
+ or changes defaults; a conflicting saved ID/alias refuses. Replay may omit this
26
+ file after removal; if supplied, its admitted profile must match the original.
27
+ When no default or explicit profile exists, an interactive terminal uses the
28
+ shared executor dialog. Creation is operation-only here; skip is not allowed.
29
+ --non-interactive, JSON and non-terminal input never ask and missing choices
30
+ refuse before project effects. Use profiles commands for explicit global saves.
31
+
32
+ The existing managed controller owns Sessions and execution. The default waits
33
+ for completion, recovery or a user/context boundary; --detach returns its
34
+ accepted receipt. Observer disconnection does not stop the controller.
35
+ --prepare-only publishes the normal project bootstrap and frozen RUN, but does
36
+ not launch a controller or provider Session. It is not a dry run and is exclusive
37
+ with --detach. A runner may then use run drive launch with its own context and
38
+ bounded stop/capture policy. Exact preparation replay never stops or replaces
39
+ an existing controller.
40
+ Use existing scoped run drive status / run control commands to observe,
41
+ answer, pause, stop or reconcile the retained RUN. Native/attached public
42
+ selection is not yet exposed; no failed route silently becomes native.`],
43
+ ["flow", `dd-flow flow - engine-owned workflow catalog
44
+
45
+ Usage:
46
+ dd-flow flow list --json
47
+ dd-flow flow show <id> --json
48
+
49
+ Inspection never opens a runtime database, initializes a home or runs agents.
50
+ The catalog reports handler registration separately from RUN readiness. A
51
+ pending handler set cannot execute; registered handlers still require selected
52
+ canon, frozen descriptor/schema admission, workspace and execution readiness.
53
+ These inspection commands do not start init or qualify an installed route.`],
54
+ ["models", `dd-flow models - reviewed seed and scoped offline observations
55
+
56
+ Usage:
57
+ dd-flow models list --json
58
+ dd-flow models show <model> --harness family --provider provider --json
59
+ dd-flow models list --harness family --provider provider --account-sha256 <digest> --observation-file /absolute/listing.json --json
60
+
61
+ No database, credentials, network, executable discovery or provider process is
62
+ opened. --seed-file selects reviewed seed-only catalog data; otherwise the
63
+ bundled adapter-derived seed is used. Families not yet curated are explicit.
64
+ Unknown seed settings are not profile defaults or model recommendations.
65
+
66
+ Observations require an exact harness/provider/account scope. A matching listed
67
+ model remains unknown for account access and flow qualification. Missing or
68
+ unavailable listing retains seed entries; a foreign scope is ignored. show
69
+ refuses an absent model rather than inventing availability. Exit 2 is invalid
70
+ input; exit 1 is missing/unreadable input or an absent selected model.`],
71
+ ["completion", `dd-flow completion - shell completion from the accepted command grammar
72
+
73
+ Usage:
74
+ dd-flow completion bash
75
+ dd-flow completion zsh
76
+ dd-flow completion fish
77
+
78
+ Prints a shell script to stdout; it does not modify shell configuration. Load
79
+ the script in your shell after reviewing it. Zsh requires compinit first.
80
+ Scripts query completion candidates with literal argv; they do not initialize
81
+ a home, open a database, inspect profiles or invoke harness processes.`],
82
+ ["harnesses", `dd-flow harnesses - static installation discovery
83
+
84
+ Usage:
85
+ dd-flow harnesses list --json
86
+ dd-flow harnesses show <family> --json
87
+ dd-flow harnesses discover [--harness family --executable /absolute/path] --json
88
+ dd-flow harnesses probe-version --harness family --allow-processes --allow-credentials --allow-writes [--executable /absolute/path --timeout-ms 3000] --json
89
+ dd-flow harnesses doctor --harness family --allow-processes --allow-credentials [--allow-services --allow-writes --executable /absolute/path] --json
90
+
91
+ Lists all six supported families, including missing installations. Multiple
92
+ installations require explicit selection. Presence does not establish version,
93
+ protocol, auth, model access or qualification. list/show/discover never launch a
94
+ process, inspect credentials, create a home or open a runtime database.
95
+ probe-version is an explicit diagnostic exception: it runs installed code only
96
+ after all three effect permissions are supplied. It bounds time/output and does
97
+ not establish protocol compatibility, account access or flow qualification.
98
+ doctor invokes the existing bundled adapter only after its classified effects
99
+ are admitted: Codex/OpenCode/Droid require services and writes; Agy requires
100
+ writes; ZCode/Grok require processes and credentials. ZCode also requires
101
+ --native-executable. OpenCode requires --state-dir for an existing daemon whose
102
+ executable binding matches; doctor never starts or stops that daemon.
103
+ For Droid, the OS ps utility must be available on PATH before doctor starts;
104
+ missing physical-settlement tooling refuses without launching a provider.
105
+ Reports are bounded/redacted observations, not native qualification or account access.
106
+ Use --timeout-ms 1..60000 to bound the diagnostic, not productive work.
107
+ Optional --provider and --account-sha256 must be supplied together. They bind
108
+ reported model names to an operator-declared, unverified scope, not an observed
109
+ credential identity. --model-observation-file explicitly publishes a standalone
110
+ snapshot usable by models list --observation-file. Listings are incomplete;
111
+ an absent adapter list is unavailable, never an empty verified inventory. No
112
+ account access or qualification is inferred; publication failure does not rerun
113
+ the admitted diagnostic. The destination must differ from --response-file.`],
114
+ ["setup", `dd-flow setup - global installation readiness
115
+
116
+ Usage:
117
+ dd-flow setup --canon-source /path/to/release-bundle --trust-file operator-trust.json --request-id ID --skip-agent-setup --non-interactive --json
118
+ dd-flow setup update --canon-source /path/to/release-bundle --trust-file operator-trust.json --request-id ID --skip-agent-setup --json
119
+ dd-flow setup status --json
120
+
121
+ The local bundle contains release-envelope.json, canon.tgz and engine.tgz.
122
+ Trust uses dd-flow/release-trust@1 and must be selected independently of the
123
+ envelope. Stable is the default channel; preview/development require --channel.
124
+ Without --skip-agent-setup, select --profile or an existing global default.
125
+ --profile-file supplies a complete validated profile for headless onboarding;
126
+ it is mutually exclusive with --profile and --skip-agent-setup. Profile files
127
+ never import credentials or silently change operator defaults.
128
+ No missing profile is replaced by an automatically selected model.
129
+ In an interactive terminal, a missing profile opens an explicit executor choice
130
+ only after the authenticated installation is committed:
131
+ profile ID/alias, file:/absolute/profile.json, create or skip. create asks for
132
+ every profile field and explicit confirmation, without probing providers.
133
+ Separate yes/no questions authorize saving and global default selection; no
134
+ settings are written by the dialog itself. JSON/JSONL output,
135
+ --non-interactive and non-terminal input never prompt. Cancellation leaves the
136
+ installation committed and onboarding pending; replay the same request to resume
137
+ or explicitly skip onboarding. The separate onboarding receipt freezes the
138
+ selected profile and save/default consent before profile effects. A completed
139
+ onboarding replay never restores later settings. Existing request-bound profile
140
+ choices keep their original identity and recovery semantics.
141
+ --save-profile-intent supplies explicit frozen profile creation/default consent
142
+ for persistence. The selected profile must match; skip conflicts. Setup retains
143
+ the complete intent in its request and uses a profiles_saved checkpoint. A
144
+ committed replay never restores settings changed after the original installation.
145
+ Without a new explicit executor choice, an exact request retry reuses its retained
146
+ executor and save/default consent rather than asking again or choosing a new default.
147
+ Status inspects the selected installation and retained cache without opening or
148
+ migrating SQLite, registering a project, discovering providers or running agents.
149
+ Installation readiness and runtime qualification are separate facts.
150
+ `],
151
+ ["profiles", `dd-flow profiles - home-only executor settings
152
+
153
+ Usage:
154
+ dd-flow profiles list --json
155
+ dd-flow profiles show <ID-or-alias> --json
156
+ dd-flow profiles create --file profile.json --expected-revision SHA256 [--set-default] --json
157
+ dd-flow profiles edit --file profile.json --expected-revision SHA256 --json
158
+ dd-flow profiles remove <ID> --expected-revision SHA256 --json
159
+ dd-flow profiles alias <alias> (--target ID | --remove) --expected-revision SHA256 --json
160
+ dd-flow profiles set-default [ID-or-alias | --clear] --expected-revision SHA256 --json
161
+
162
+ Read the current revision with profiles list before changing settings. Writes
163
+ are atomic and reject concurrent/stale changes. Aliases point directly to IDs,
164
+ not other aliases. Profile files use dd-flow/agent-profile@1 and reject secret
165
+ fields. Existing legacy IDs are imported on the first successful write without
166
+ editing their files. Thereafter profile-settings.json is the sole owner.
167
+ Existing RUNs use frozen snapshots, not mutable profile settings. This command
168
+ never registers a project, selects a model automatically or creates a runtime DB.`],
2
169
  ["runtime scope", `Usage:
3
170
  dd-flow runtime scope fence --scope-id EVAL_ID --request-id ID --json
4
171
  dd-flow runtime scope status --scope-id EVAL_ID --json
@@ -197,7 +364,7 @@ Usage:
197
364
  dd-flow run recovery inspect|begin|seal|capture|resume <RUN-ID|RUN-short-id> --project-root <root> --json
198
365
  dd-flow run snapshot create <RUN-ID|RUN-short-id> (--stage-entry <stage>|--candidate|--incomplete|--recovery-id <RCV-ID>) --project-root <root> --output <directory> --json
199
366
  dd-flow run snapshot restore --snapshot <directory> --project-root <prepared-root> [--recovery-id <RCV-ID>] --json
200
- dd-flow run snapshot bootstrap create --project-root <root> --output <directory> --json
367
+ dd-flow run snapshot bootstrap create --project-root <root> --output <directory> [--flow sdlc|mb-init] --json
201
368
  dd-flow run snapshot bootstrap restore --snapshot <directory> --project-root <prepared-root> --json
202
369
  dd-flow run fork --from <sealed-stage-entry-snapshot> --output <empty-directory> --engine-version <exact-version> --request-id <id> [--integrity-checksum <sha256>] --json
203
370
  dd-flow run timeline <RUN-ID|RUN-short-id> --project-root <root> --json
@@ -559,8 +726,12 @@ Examples:
559
726
 
560
727
  Usage:
561
728
  dd-flow memory permissions preflight --root <project-root> --memory-bank <path> [--tasks <path>] --flow <flow> --mode <mode> --json
729
+ dd-flow memory finish integrate --run <run-id> --project-root <project-root> --json
730
+ dd-flow memory finish evidence --run <run-id> --project-root <project-root> --json
562
731
 
563
- permissions preflight checks project, Memory Bank, and optional .tasks read/write permissions before memory flows mutate files. It never runs privileged repair commands. A completed assessment returns JSON on stdout with exit_code 0 when the flow can continue and exit_code 1 when permission blockers are found. Runtime/configuration mistakes exit 2 as structured errors.`
732
+ permissions preflight checks project, Memory Bank, and optional .tasks read/write permissions before memory flows mutate files. It never runs privileged repair commands. A completed assessment returns JSON on stdout with exit_code 0 when the flow can continue and exit_code 1 when permission blockers are found. Runtime/configuration mistakes exit 2 as structured errors.
733
+
734
+ finish integrate commits only the accepted Memory Bank and owned lint configuration, then performs the retained local integration route. It preserves unrelated files and never pushes or changes Git identity/configuration. An uncertain original Git effect must be observed, not blindly repeated. finish evidence then publishes actual coverage, integration and ordinary-entry preparation references; neither command accepts the finish result or completes the RUN.`
564
735
  ],
565
736
  [
566
737
  "memory permissions",
@@ -663,10 +834,73 @@ worktree plan suggests a project-scoped service checkout under DD_FLOW_HOME/proj
663
834
  ]
664
835
  ]);
665
836
  export function helpForArgs(args) {
666
- const helpIndex = args.findIndex((arg) => arg === "--help" || arg === "-h");
667
- if (helpIndex === -1) {
837
+ return resolveHelp(args)?.text;
838
+ }
839
+ export function hasHelpIntent(args) {
840
+ const end = args.indexOf("--");
841
+ return args.slice(0, end < 0 ? args.length : end).some(arg => arg === "--help" || arg === "-h");
842
+ }
843
+ /** Pure early resolver: no filesystem, runtime context, process dispatch or output-file access. */
844
+ export function resolveHelp(args) {
845
+ if (!hasHelpIntent(args))
668
846
  return undefined;
847
+ const end = args.indexOf("--"), tokens = args.slice(0, end < 0 ? args.length : end);
848
+ const positions = [], selectors = [], supplied = [];
849
+ let json = false;
850
+ const switches = new Set([...globalOptionDocumentation.filter(o => o.kind === "switch").map(o => o.name),
851
+ ...Object.values(commandInputs).flatMap(input => input.switches)]);
852
+ for (let index = 0; index < tokens.length; index++) {
853
+ const token = tokens[index];
854
+ if (token === "--help" || token === "-h")
855
+ continue;
856
+ if (token === "--option" || token.startsWith("--option=")) {
857
+ const value = token.startsWith("--option=") ? token.slice(9) : tokens[++index];
858
+ if (!value || value === "--help" || value === "-h")
859
+ throw helpUsage("--option requires one option selector");
860
+ selectors.push(value.replace(/^--/, ""));
861
+ continue;
862
+ }
863
+ if (token.startsWith("--")) {
864
+ const name = token.slice(2).split("=", 1)[0];
865
+ supplied.push(name);
866
+ if (token === "--json")
867
+ json = true;
868
+ if (!token.includes("=") && !switches.has(name) && tokens[index + 1] && !tokens[index + 1].startsWith("-"))
869
+ index++;
870
+ }
871
+ else if (token.startsWith("-"))
872
+ throw helpUsage(`Unknown short option: ${token}`);
873
+ else
874
+ positions.push(token);
669
875
  }
670
- const path = args.slice(0, helpIndex).filter((arg) => !arg.startsWith("--")).join(" ");
671
- return helpPages.get(path) ?? helpPages.get(path.split(" ").slice(0, 2).join(" ")) ?? helpPages.get("");
876
+ if (selectors.length > 1)
877
+ throw helpUsage("--option must occur once");
878
+ const selected = commandKeyForPositions(positions);
879
+ const command = selected ?? positions.join(" ");
880
+ const commands = Object.keys(commandInputs).filter(key => !command || key === command || key.startsWith(`${command} `));
881
+ if (command && commands.length === 0)
882
+ throw helpUsage(`Unknown help command: ${command}`);
883
+ const optionMap = new Map(optionsForCommandTree(command).map(option => [option.name, option]));
884
+ // Invalid response transport is intentionally irrelevant to help, including missing/repeated values.
885
+ for (const name of supplied)
886
+ if (!optionMap.has(name))
887
+ throw helpUsage(`Unknown option --${name} for ${command || "root"}`);
888
+ const option = selectors.length ? optionMap.get(selectors[0]) : null;
889
+ if (selectors.length && !option)
890
+ throw helpUsage(`Unknown option selector: ${selectors[0]}`);
891
+ const options = [...optionMap.values()].sort((a, b) => a.name.localeCompare(b.name, "en"));
892
+ const input = selected ? commandInputs[selected] : undefined;
893
+ const canonical = commandAliases[command] ?? command;
894
+ const pageKey = [...helpPages.keys()].filter(key => key && (canonical === key || canonical.startsWith(`${key} `)))
895
+ .sort((a, b) => b.length - a.length)[0] ?? "";
896
+ const detail = (value) => `--${value.name}${value.kind === "value" ? " <value>" : ""}${value.required ? " (required)" : ""}${value.repeatable ? " (repeatable)" : ""}\n ${value.description}${value.choices.length ? `\n Allowed: ${value.choices.join(", ")}` : ""}`;
897
+ const usage = input ? `\nExact command: dd-flow ${command}${input.positions[0] ? ` <argument>${input.positions[0] > 1 ? ` × ${input.positions[0]}` : ""}` : ""}\n` : "";
898
+ return { json,
899
+ text: option ? `dd-flow ${command} --option ${option.name} --help\n\n${detail(option)}`
900
+ : `${helpPages.get(pageKey)}${usage}\n${input?.retired ? `Retired: ${input.retired}\n` : ""}\n${command ? "" : "Command paths:\n"}${input ? "" : commands.map(key => ` ${key}`).join("\n")}\n\nOptions:\n${options.map(detail).join("\n")}`,
901
+ data: { schema_id: "dd-flow/cli-help@1", command, alias_of: commandAliases[command] ?? null, commands, options, option: option ?? null,
902
+ router_native: selected ? routerNativeRoute(selected) : true, retired: input?.retired ?? null } };
903
+ }
904
+ function helpUsage(message) {
905
+ return new AppError("usage", `${message}; use dd-flow --help`, 2, { phase: "help", effect: "no_effect", recoverable: true, help_topic: "dd-flow --help" });
672
906
  }
@@ -32,11 +32,42 @@ export function prepareError(error, input = {}) {
32
32
  phase: "prepare", effect: "no_effect", recoverable: true, ...input, cause: code ?? String(error)
33
33
  });
34
34
  }
35
- export function prepareTextFile(file, label = "input file") {
36
- const prepared = prepareFileBytes(file, label);
37
- return { file: prepared.file, text: prepared.bytes.toString("utf8") };
35
+ export function prepareTextFile(file, label = "input file", maxBytes) {
36
+ const prepared = prepareFileBytes(file, label, maxBytes);
37
+ if (maxBytes === undefined)
38
+ return { file: prepared.file, text: prepared.bytes.toString("utf8") };
39
+ try {
40
+ return { file: prepared.file, text: new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(prepared.bytes) };
41
+ }
42
+ catch {
43
+ return prepareError(new AppError("validation", `${label} must contain valid UTF-8`, 2), { file: prepared.file, label });
44
+ }
38
45
  }
39
- export function prepareFileBytes(file, label = "input file") {
46
+ export async function readBoundedUtf8Stream(stream, maxBytes) {
47
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 0)
48
+ throw new AppError("usage", "Invalid input byte bound", 2);
49
+ const decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
50
+ let data = "", byteLength = 0;
51
+ for await (const chunk of stream) {
52
+ const bytes = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
53
+ byteLength += bytes.length;
54
+ if (byteLength > maxBytes)
55
+ throw new AppError("usage", "Standard input exceeds its byte bound", 2);
56
+ try {
57
+ data += decoder.decode(bytes, { stream: true });
58
+ }
59
+ catch {
60
+ throw new AppError("validation", "Standard input must contain valid UTF-8", 2);
61
+ }
62
+ }
63
+ try {
64
+ return data + decoder.decode();
65
+ }
66
+ catch {
67
+ throw new AppError("validation", "Standard input must contain valid UTF-8", 2);
68
+ }
69
+ }
70
+ export function prepareFileBytes(file, label = "input file", maxBytes) {
40
71
  const absolute = path.resolve(file);
41
72
  let descriptor;
42
73
  try {
@@ -45,7 +76,25 @@ export function prepareFileBytes(file, label = "input file") {
45
76
  if (!stat.isFile()) {
46
77
  throw new AppError("input_file_not_regular", `${label} must be a readable regular file: ${absolute}`, 2, { file: absolute, label });
47
78
  }
48
- return { file: absolute, bytes: fs.readFileSync(descriptor) };
79
+ if (maxBytes === undefined)
80
+ return { file: absolute, bytes: fs.readFileSync(descriptor) };
81
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 0)
82
+ throw new AppError("usage", "Invalid input byte bound", 2);
83
+ const oversized = () => new AppError("usage", `${label} exceeds its byte bound`, 2);
84
+ if (stat.size > maxBytes)
85
+ throw oversized();
86
+ // Read at most one extra byte: the file can grow after fstat.
87
+ const buffer = Buffer.alloc(maxBytes + 1);
88
+ let length = 0;
89
+ while (length < buffer.length) {
90
+ const count = fs.readSync(descriptor, buffer, length, buffer.length - length, null);
91
+ if (!count)
92
+ break;
93
+ length += count;
94
+ }
95
+ if (length > maxBytes)
96
+ throw oversized();
97
+ return { file: absolute, bytes: buffer.subarray(0, length) };
49
98
  }
50
99
  catch (error) {
51
100
  if (error?.code === "ENOENT") {
@@ -0,0 +1,44 @@
1
+ import { prepareCommandRoute } from "./command-inputs.js";
2
+ import { parseOutputOptions } from "./output-options.js";
3
+ import { readBoundedUtf8Stream, prepareJsonText } from "./input-preparation.js";
4
+ import { PreparedInstalledFlowSource } from "../services/installed-flow-source.js";
5
+ import { hybridDigest } from "../services/hybrid-contracts.js";
6
+ import { AppError, errorRecord } from "../shared/errors.js";
7
+ import { writePreparationError } from "./error-output.js";
8
+ import { memoryInitStartupInputSchemas } from "../services/memory-init-startup-custody.js";
9
+ /** Executing engine's real handler admission only. The caller owns independent
10
+ * release/source selection; this command never opens storage or creates a RUN. */
11
+ export async function runMemoryFlowAdmissionCli(args, io = process) {
12
+ try {
13
+ const output = parseOutputOptions(args), route = prepareCommandRoute(output.args);
14
+ if (route.key !== "runtime flow admit" || output.responseFile || output.progressJsonl) {
15
+ throw new AppError("usage", "Flow admission accepts bounded stdin and stdout output only", 2, { effect: "no_effect" });
16
+ }
17
+ const input = prepareJsonText(await readBoundedUtf8Stream(io.stdin, 64 * 1024 * 1024), { file: "<stdin>", label: "flow admission" }).value;
18
+ if (!input || typeof input !== "object" || Array.isArray(input)
19
+ || !["source,source_sha256", "source,source_sha256,startup_input_schema"].includes(Object.keys(input).sort().join())) {
20
+ throw new AppError("usage", "Flow admission requires an exact source snapshot and independent digest", 2, { effect: "no_effect" });
21
+ }
22
+ const selected = input;
23
+ const startupSchema = memoryInitStartupInputSchemas.find(schema => schema === selected.startup_input_schema);
24
+ if (Object.hasOwn(selected, "startup_input_schema") && startupSchema === undefined) {
25
+ throw new AppError("usage", "Executing engine does not support the requested startup input schema", 2, { effect: "no_effect" });
26
+ }
27
+ if (typeof selected.source_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(selected.source_sha256)) {
28
+ throw new AppError("usage", "Flow admission requires a SHA-256 source digest", 2, { effect: "no_effect" });
29
+ }
30
+ const source = PreparedInstalledFlowSource.restoreRetained(selected.source, selected.source_sha256);
31
+ const flow = source.resolveRegisteredFlow();
32
+ const facts = { schema_id: startupSchema === undefined ? "dd-flow/memory-init-engine-flow@1" : "dd-flow/memory-init-engine-flow@2",
33
+ ...(startupSchema === undefined ? {} : { startup_input_schema: startupSchema }),
34
+ flow_id: "mb-init", source_sha256: source.sha256,
35
+ descriptor_sha256: source.descriptorReference().sha256, stages: flow.descriptor.stages.map(stage => stage.id) };
36
+ io.stdout.write(`${JSON.stringify({ ok: true, action: "runtime_flow_admit", facts, sha256: hybridDigest(facts) }, null, output.json ? undefined : 2)}\n`);
37
+ return 0;
38
+ }
39
+ catch (error) {
40
+ const record = errorRecord(error);
41
+ writePreparationError(io, args, record);
42
+ return record.exitCode;
43
+ }
44
+ }
@@ -0,0 +1,78 @@
1
+ import path from "node:path";
2
+ import { AppError } from "../shared/errors.js";
3
+ import { hybridDigest } from "../services/hybrid-contracts.js";
4
+ import { prepareCommandRoute } from "./command-inputs.js";
5
+ const stages = new Set(["preflight", "discover", "compose", "verify", "review", "finish"]);
6
+ function refuse(message) {
7
+ throw new AppError("usage", message, 2, { phase: "prepare", effect: "no_effect" });
8
+ }
9
+ /** Pure invocation preparation. File bytes, stored replay and productive
10
+ * authority remain with their existing owners; no ambient defaults here. */
11
+ export function prepareMemoryInitInvocation(args) {
12
+ const route = prepareCommandRoute(args);
13
+ if (!["init", "flow mb-init"].includes(route.key))
14
+ refuse("Use init or flow mb-init");
15
+ const options = route.parsed.options;
16
+ const value = (name) => options.get(name)?.[0];
17
+ const scope = { projectRoot: value("project-root"), workspaceRoot: value("workspace-root"), requestId: value("request-id") };
18
+ if (![scope.projectRoot, scope.workspaceRoot].every(path.isAbsolute)
19
+ || !/^[A-Za-z0-9][A-Za-z0-9_.-]{0,95}$/.test(scope.requestId))
20
+ refuse("Init needs absolute roots and a bounded request id");
21
+ const execution = {};
22
+ const maxParallel = value("max-parallel");
23
+ const delegation = value("delegation"), nativeConfigHome = value("native-config-home");
24
+ if (maxParallel !== undefined || delegation !== undefined)
25
+ execution.delegation = {
26
+ mode: delegation === "native" ? "native" : "external", max_parallel: Number(maxParallel ?? 1)
27
+ };
28
+ if (delegation === "native" && Number(maxParallel ?? 1) > 15)
29
+ refuse("Native concurrency must be 1..15");
30
+ if (nativeConfigHome !== undefined && (!path.isAbsolute(nativeConfigHome) || delegation !== "native")
31
+ || options.has("allow-live-probe") && delegation !== "native")
32
+ refuse("Native probe options require explicit native delegation; an optional config home must be absolute");
33
+ const profile = value("profile");
34
+ const profileFile = value("profile-file");
35
+ if (profileFile !== undefined && (!path.isAbsolute(profileFile) || profile !== undefined))
36
+ refuse("--profile-file must be absolute and is exclusive with --profile");
37
+ if (profile !== undefined)
38
+ execution.rootProfile = profile;
39
+ for (const assignment of options.get("stage-profile") ?? []) {
40
+ const at = assignment.indexOf("="), stage = assignment.slice(0, at), profile = assignment.slice(at + 1);
41
+ if (at < 1 || !stages.has(stage) || !profile.trim() || execution.stageProfiles?.[stage] !== undefined)
42
+ refuse("--stage-profile requires a unique stage=profile assignment");
43
+ (execution.stageProfiles ??= {})[stage] = profile;
44
+ }
45
+ if (options.has("work-profile")) {
46
+ execution.workProfiles = [...options.get("work-profile")];
47
+ if (new Set(execution.workProfiles).size !== execution.workProfiles.length)
48
+ refuse("--work-profile must not repeat a profile");
49
+ }
50
+ const intakeFile = value("intake-file"), intakeSha256 = value("intake-sha256");
51
+ if (Boolean(intakeFile) !== Boolean(intakeSha256)
52
+ || intakeSha256 !== undefined && !/^[a-f0-9]{64}$/.test(intakeSha256)
53
+ || intakeFile !== undefined && !path.isAbsolute(intakeFile))
54
+ refuse("Original intake needs an absolute --intake-file and --intake-sha256 pair");
55
+ const gitRoute = value("git-route"), integrationBranch = value("integration-branch");
56
+ if (Boolean(gitRoute) !== Boolean(integrationBranch))
57
+ refuse("--git-route and --integration-branch must be supplied together");
58
+ const gitPolicy = gitRoute === undefined ? undefined : {
59
+ route: gitRoute, integrationBranch: integrationBranch
60
+ };
61
+ if (options.has("prepare-only") && options.has("detach"))
62
+ refuse("--prepare-only does not launch a controller and is exclusive with --detach");
63
+ return { scope, execution, gitPolicy, intakeFile, intakeSha256, profileFile, nativeConfigHome, allowLiveProbe: options.has("allow-live-probe"), nonInteractive: options.has("non-interactive"), detach: options.has("detach"), prepareOnly: options.has("prepare-only") };
64
+ }
65
+ /** Omitted selectors replay the retained choices, never current aliases.
66
+ * Supplied selectors must equal the original raw selection, not merely resolve
67
+ * to today's equivalent profile. Intake paths are locators, hashes bind bytes. */
68
+ export function assertMemoryInitInvocationReplay(invocation, original, intakeSha256) {
69
+ if (hybridDigest(invocation.scope) !== hybridDigest(original.scope)
70
+ || invocation.intakeSha256 !== undefined && invocation.intakeSha256 !== intakeSha256
71
+ || invocation.gitPolicy !== undefined && hybridDigest(invocation.gitPolicy) !== hybridDigest(original.git_policy)
72
+ || Object.entries(invocation.execution).some(([key, value]) => !Object.hasOwn(original.execution, key)
73
+ || hybridDigest(value) !== hybridDigest(key === "delegation" && invocation.execution.delegation?.mode === "native"
74
+ ? { mode: original.execution.delegation?.mode, max_parallel: original.execution.delegation?.max_parallel }
75
+ : original.execution[key]))) {
76
+ throw new AppError("memory_init_request_conflict", "Request id belongs to different original init inputs", 1, { effect: "no_effect", next_action: "replay_exact_request_or_choose_new_id" });
77
+ }
78
+ }