@deksden-com/dd-flow-cli 0.9.0-beta.9 → 0.9.0-beta.91
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.
- package/CHANGELOG.md +467 -0
- package/README.md +65 -0
- package/dist/build-info.json +8 -8
- package/dist/cli/command-inputs.js +305 -0
- package/dist/cli/help.js +89 -13
- package/dist/cli/hook-ingress.js +82 -0
- package/dist/cli/input-preparation.js +116 -0
- package/dist/cli/run-cli.js +1421 -384
- package/dist/cli.js +6 -2
- package/dist/harness-runtime/bin/dd-agy.mjs +37 -0
- package/dist/harness-runtime/bin/dd-codex.mjs +25 -0
- package/dist/harness-runtime/bin/dd-droid.mjs +33 -0
- package/dist/harness-runtime/bin/dd-grok.mjs +30 -0
- package/dist/harness-runtime/bin/dd-opencode.mjs +21 -0
- package/dist/harness-runtime/bin/dd-zcode.mjs +83 -0
- package/dist/harness-runtime/lib/daemon-operations.mjs +215 -0
- package/dist/harness-runtime/lib/dd-agy-daemon.mjs +423 -0
- package/dist/harness-runtime/lib/dd-agy.mjs +59 -0
- package/dist/harness-runtime/lib/dd-codex-daemon.d.mts +1 -0
- package/dist/harness-runtime/lib/dd-codex-daemon.mjs +146 -0
- package/dist/harness-runtime/lib/dd-codex.mjs +562 -0
- package/dist/harness-runtime/lib/dd-droid-daemon.mjs +125 -0
- package/dist/harness-runtime/lib/dd-droid.mjs +471 -0
- package/dist/harness-runtime/lib/dd-grok-daemon.mjs +274 -0
- package/dist/harness-runtime/lib/dd-grok.mjs +174 -0
- package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +198 -0
- package/dist/harness-runtime/lib/dd-opencode.mjs +98 -0
- package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +644 -0
- package/dist/harness-runtime/lib/dd-zcode.mjs +910 -0
- package/dist/harness-runtime/lib/delegation-instructions.d.mts +10 -0
- package/dist/harness-runtime/lib/delegation-instructions.mjs +130 -0
- package/dist/harness-runtime/lib/dispatch-fence.mjs +14 -0
- package/dist/harness-runtime/lib/driver-recovery.mjs +129 -0
- package/dist/harness-runtime/lib/droid-observation.mjs +66 -0
- package/dist/harness-runtime/lib/managed-daemon.mjs +260 -0
- package/dist/harness-runtime/lib/model-observations.mjs +77 -0
- package/dist/harness-runtime/lib/native-hook-command.d.mts +1 -0
- package/dist/harness-runtime/lib/native-hook-command.mjs +34 -0
- package/dist/harness-runtime/lib/observation-clock.mjs +36 -0
- package/dist/harness-runtime/lib/operation-context.mjs +5 -0
- package/dist/harness-runtime/lib/operation-errors.mjs +19 -0
- package/dist/harness-runtime/lib/process-json.mjs +70 -0
- package/dist/harness-runtime/lib/process-snapshot.mjs +10 -0
- package/dist/harness-runtime/lib/runner-events.mjs +200 -0
- package/dist/harness-runtime/lib/runner-lock.mjs +42 -0
- package/dist/harness-runtime/lib/session-settlement.mjs +30 -0
- package/dist/harness-runtime/lib/tool-observations.d.mts +17 -0
- package/dist/harness-runtime/lib/tool-observations.mjs +153 -0
- package/dist/schemas/agent-profile.schema.json +1 -1
- package/dist/schemas/code-review-result.schema.json +2 -2
- package/dist/schemas/code-work-batch.schema.json +4 -3
- package/dist/schemas/code-work-result.schema.json +4 -4
- package/dist/schemas/plan-review-result.schema.json +2 -2
- package/dist/schemas/run-control-receipt.schema.json +99 -0
- package/dist/schemas/run-control-request.schema.json +36 -0
- package/dist/schemas/vnext-protocol-plan.schema.json +2 -2
- package/dist/services/canon.js +11 -8
- package/dist/services/cleanup.js +57 -13
- package/dist/services/cli-operation-classifier.js +22 -24
- package/dist/services/code-checks.js +543 -96
- package/dist/services/codex-hook-delivery.js +28 -0
- package/dist/services/command-context.js +80 -0
- package/dist/services/config.js +11 -8
- package/dist/services/continuation-outcome.js +20 -0
- package/dist/services/controller-fanout.js +132 -0
- package/dist/services/dashboard.js +103 -31
- package/dist/services/engines.js +121 -76
- package/dist/services/eval-snapshots.js +750 -73
- package/dist/services/execution-policy.js +170 -0
- package/dist/services/external-work-launch.js +110 -0
- package/dist/services/harness-adapter.js +147 -24
- package/dist/services/harness-config.js +2 -0
- package/dist/services/hooks.js +587 -299
- package/dist/services/lanes.js +61 -53
- package/dist/services/lifecycle-command.js +103 -17
- package/dist/services/lifecycle-contract.js +30 -0
- package/dist/services/lifecycle-invocations.js +1122 -0
- package/dist/services/managed-daemon-binding.js +38 -0
- package/dist/services/managed-processes.js +283 -27
- package/dist/services/merge-queue.js +179 -104
- package/dist/services/merge-server.js +73 -28
- package/dist/services/migrations.js +14 -9
- package/dist/services/native-daemon-history.js +49 -0
- package/dist/services/native-session-control.js +39 -0
- package/dist/services/plan-runtime.js +19 -8
- package/dist/services/plans.js +28 -25
- package/dist/services/projects.js +18 -5
- package/dist/services/prompts.js +23 -16
- package/dist/services/protocols.js +64 -20
- package/dist/services/recovery-observation-budget.js +61 -0
- package/dist/services/recovery-snapshot-database.js +107 -0
- package/dist/services/repair-intents.js +40 -0
- package/dist/services/run-control-receipt.js +56 -0
- package/dist/services/run-control-worker.js +363 -0
- package/dist/services/run-control.js +876 -0
- package/dist/services/run-controller-adapter.js +222 -0
- package/dist/services/run-controller-capture.js +134 -0
- package/dist/services/run-controller-process.js +189 -0
- package/dist/services/run-controller-recovery.js +222 -0
- package/dist/services/run-controller-state.js +36 -0
- package/dist/services/run-controller.js +793 -0
- package/dist/services/run-engine-bindings.js +1 -1
- package/dist/services/run-fork.js +138 -0
- package/dist/services/run-observations.js +112 -0
- package/dist/services/run-recovery-runtime.js +69 -0
- package/dist/services/run-recovery.js +343 -0
- package/dist/services/runs.js +368 -74
- package/dist/services/runtime-budget.js +434 -0
- package/dist/services/runtime-command.js +43 -0
- package/dist/services/runtime-scope-capture.js +50 -0
- package/dist/services/runtime-scope-control.js +450 -0
- package/dist/services/runtime-scope-resume.js +565 -0
- package/dist/services/runtime-scope-stop.js +99 -0
- package/dist/services/runtime-scope-worker.js +243 -0
- package/dist/services/runtime-service.js +97 -0
- package/dist/services/schema-validation.js +10 -8
- package/dist/services/sessions.js +35 -69
- package/dist/services/stage-blocker.js +17 -7
- package/dist/services/stage-context.js +44 -18
- package/dist/services/stage-lifecycle.js +99 -102
- package/dist/services/stage-pause.js +84 -55
- package/dist/services/stage-work-graph.js +35 -0
- package/dist/services/usage.js +37 -93
- package/dist/services/vnext-code-review.js +195 -88
- package/dist/services/vnext-code.js +285 -252
- package/dist/services/vnext-execution-profile.js +5 -3
- package/dist/services/vnext-fanout.js +160 -17
- package/dist/services/vnext-merge.js +291 -104
- package/dist/services/vnext-plan-review.js +139 -81
- package/dist/services/vnext-plan.js +138 -69
- package/dist/services/vnext-protocolize.js +129 -56
- package/dist/services/vnext-specify.js +88 -65
- package/dist/services/work-registry.js +716 -168
- package/dist/services/workspace-bootstrap.js +76 -0
- package/dist/services/worktrees.js +85 -35
- package/dist/shared/entity-references.js +8 -0
- package/dist/shared/errors.js +12 -0
- package/dist/storage/database.js +459 -32
- package/dist/storage/paths.js +17 -4
- package/dist/storage/work-references.js +23 -0
- package/dist/storage/writer-contract.js +77 -0
- package/dist/storage/writer-migration.js +102 -0
- package/package.json +24 -13
- package/tools/repair-paused-run-status.mjs +59 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { AppError } from "../shared/errors.js";
|
|
2
|
+
import { parseCommandArgs } from "../services/lifecycle-command.js";
|
|
3
|
+
import { lifecycleInternalOptions, lifecycleRouteForOperation } from "../services/lifecycle-contract.js";
|
|
4
|
+
import { isUpgradeAllowlisted } from "../services/cli-operation-classifier.js";
|
|
5
|
+
const words = (value) => value.split(" ").filter(Boolean);
|
|
6
|
+
const route = (positions, required = "", values = "", switches = "", repeatable = "", enums = {}) => ({
|
|
7
|
+
positions: typeof positions === "number" ? [positions, positions] : positions,
|
|
8
|
+
required: words(required), values: words(`${required} ${values}`), switches: words(switches), repeatable: words(repeatable), enums
|
|
9
|
+
});
|
|
10
|
+
const project = "project-root";
|
|
11
|
+
const scoped = "project-root"; // Optional when the router resolves a unique retained scope.
|
|
12
|
+
const lifecycle = lifecycleInternalOptions.join(" ");
|
|
13
|
+
const worker = "worker-id";
|
|
14
|
+
const control = "project-root run";
|
|
15
|
+
/** Path-shaped arguments default to physical paths unless the route explicitly
|
|
16
|
+
* opts into contextualPaths. This inventory does not expand arbitrary strings. */
|
|
17
|
+
export const physicalPathOptions = new Set(words("root project-root workspace-root workspace-path path dir file schema-dir output result-file semantic-file data decision-file verification-file reason-file task-file intake-file context-file observations-file observation-file summary-file question-file answer-file payload-file json-file task-profile-file execution-routing-file protocol-override-file manifest-file routing-file config-file input-file report-file snapshot-file output-dir state-dir capture-root capture-path destination source archive snapshot plan-file backup-path database backup source-home target-home stdout stderr adapter-executable memory-bank flow stage-report dashboard report"));
|
|
18
|
+
export const commandInputs = {
|
|
19
|
+
"version": route(0),
|
|
20
|
+
"status": route(0, "", "root project-root", "check-registry"),
|
|
21
|
+
"project register": route(0, "root"),
|
|
22
|
+
"project status": route(0, "root"),
|
|
23
|
+
"project summary": route(0, project, "write"),
|
|
24
|
+
"project resolve": route(1),
|
|
25
|
+
"project archive": route([0, 1], "reason", "root"),
|
|
26
|
+
"project migrate-ids": route(0, "root", "", "apply"),
|
|
27
|
+
"project config status": route(0, project),
|
|
28
|
+
"project config set": route(0, `${project} key value`),
|
|
29
|
+
"protocol register": route(1, project, "workspace-path"),
|
|
30
|
+
"protocol status": route(1, "", scoped),
|
|
31
|
+
"protocol branch-status": route([0, 1], "", `${scoped} path`),
|
|
32
|
+
"protocol ready": route(0, project),
|
|
33
|
+
"protocol blockers": route(1, project),
|
|
34
|
+
"protocol implement": route(1, "", `${scoped} reason`, "force"),
|
|
35
|
+
"protocol ready-for-merge": route(1, "", scoped),
|
|
36
|
+
"protocol transition": route(1, "to", `${scoped} payload-file json-file reason`, "force"),
|
|
37
|
+
"transition": route(1, "to", `${scoped} payload-file json-file reason`, "force"),
|
|
38
|
+
"protocol sync-from-run": route(1, "run", `${scoped} target`),
|
|
39
|
+
"protocol cancel": route(1, "reason", `${scoped} close-sessions cancel-queue release-locks worktree`, "force"),
|
|
40
|
+
"plan status": route(1, "", scoped),
|
|
41
|
+
"plan reviews": { ...route(0), retired: "PLAN review dispatch moved to: dd-flow plan-review dispatch <RUN>" },
|
|
42
|
+
"plan item start": route(2, "", scoped),
|
|
43
|
+
"plan item done": route(2, "summary", `${scoped} evidence`, "", "evidence"),
|
|
44
|
+
"plan item block": route(2, "reason user-required", scoped),
|
|
45
|
+
"plan item skip": route(2, "reason", scoped),
|
|
46
|
+
"plan-review dispatch": route(1, "", scoped),
|
|
47
|
+
"prompt render": { ...route(0, `${project} run stage profile`, "workspace-root task-file plan-item"), contextualPaths: words("project-root workspace-root task-file") },
|
|
48
|
+
"stage start": { ...route([0, 1], `${project} stage`, `${lifecycle} dir subject intake-file context-file context-sha256`, "bootstrap intake-stdin require-session-binding"), contextualPaths: words("project-root intake-file context-file") },
|
|
49
|
+
"stage finish": { ...route(1, `${project} stage`, `${lifecycle} dir semantic-file data result-file outcome decision-file verification-file retry-check reason reason-file request work`, "result-stdin"), contextualPaths: words("project-root semantic-file result-file decision-file verification-file reason-file") },
|
|
50
|
+
"stage pause": { ...route(1, `${project} stage work`, `${lifecycle} question-file`, "question-stdin"), contextualPaths: words("project-root question-file") },
|
|
51
|
+
"stage resume": { ...route(1, `${project} stage work`, `${lifecycle} answer-file`, "answer-stdin"), contextualPaths: words("project-root answer-file") },
|
|
52
|
+
"stage block": { ...route(1, `${project} stage work kind code`, "summary-file", "summary-stdin retryable", "", { kind: ["engine", "harness", "environment"] }), contextualPaths: words("project-root summary-file") },
|
|
53
|
+
"stage unblock": route(1, `${project} stage work`),
|
|
54
|
+
"stage fanout status": route(1, "stage", scoped),
|
|
55
|
+
"stage fanout dispatch": route(1, "stage", scoped),
|
|
56
|
+
"stage fanout reconcile": { ...route(1, "stage observations-file", scoped), contextualPaths: words("project-root observations-file") },
|
|
57
|
+
"stage native observe": { ...route(1, "stage observations-file", scoped), contextualPaths: words("project-root observations-file") },
|
|
58
|
+
"work status": route(1, project),
|
|
59
|
+
"work add-batch": { ...route(0, "parent file", scoped), contextualPaths: words("project-root file") },
|
|
60
|
+
"work ls": route(0, "", `${scoped} run parent status limit`, "ready include-results", "", { status: ["created", "running", "paused", "completed", "failed", "cancelled"] }),
|
|
61
|
+
"work show": route(1, "", scoped),
|
|
62
|
+
"work repair add": { ...route(0, "run", `${scoped} origin-work from-check from-finding from-unresolved check-ref verification-file task-file`, "task-stdin", "origin-work from-finding from-unresolved check-ref"), contextualPaths: words("project-root verification-file task-file") },
|
|
63
|
+
"work deps add": route(1, "on", scoped, "", "on"),
|
|
64
|
+
"work deps remove": route(1, "on", scoped, "", "on"),
|
|
65
|
+
"work deps list": route(1, "", scoped),
|
|
66
|
+
"work deps clear": route(1, "", scoped),
|
|
67
|
+
"work delete": route(1, "", scoped),
|
|
68
|
+
"work launch": route(1, "", `${scoped} stage`),
|
|
69
|
+
"work start": { ...route(1, "", `${scoped} ${lifecycle} recovery-id`), contextualPaths: ["project-root"] },
|
|
70
|
+
"work finish": { ...route(1, "", `${scoped} ${lifecycle} result-file retry-check reason reason-file`, "result-stdin"), contextualPaths: words("project-root result-file reason-file") },
|
|
71
|
+
"work fail": { ...route(1, "reason", `${scoped} ${lifecycle}`), contextualPaths: ["project-root"] },
|
|
72
|
+
"work cancel": route(1, "reason", scoped),
|
|
73
|
+
"work retry": route(1, "reason", scoped),
|
|
74
|
+
"session register": { ...route(0, "", `${scoped} ${lifecycle} payload-base64 payload-json payload-file session-id`), contextualPaths: words("project-root payload-file") },
|
|
75
|
+
"session status": route(0, project, "session-id worker-id"),
|
|
76
|
+
"session stop": route(0, `${project} session-id reason`),
|
|
77
|
+
"session stop-worker": route(0, `${project} worker-id reason`),
|
|
78
|
+
"session usage sync": route(0, project, "session-id"),
|
|
79
|
+
"run start": route(0, `${project} flow-kind subject-type subject-id slug`, "workspace-root next-action preset task-profile-file execution-routing-file protocol-override-file flag", "", "flag"),
|
|
80
|
+
"run prepare-vnext-specify": route(0, `${project} slug`, "execution-routing-file"),
|
|
81
|
+
"run status": route(1, project),
|
|
82
|
+
"run list": route(0, project),
|
|
83
|
+
"run timeline": route(1, project, "hide", "", "hide"),
|
|
84
|
+
"run config status": route(1, project),
|
|
85
|
+
"run config set": route(1, `${project} key value reason`),
|
|
86
|
+
"run vars ls": route(1, project),
|
|
87
|
+
"run vars get": route(1, `${project} key`),
|
|
88
|
+
"run vars set": route(1, `${project} key value`),
|
|
89
|
+
"run flags status": route(1, project),
|
|
90
|
+
"run flags revise": route(1, `${project} expected-revision idempotency-key`, "flag preset reason", "allow-downgrade", "flag"),
|
|
91
|
+
"run attach-stage": route(1, `${project} stage dir status`, "data-schema-id"),
|
|
92
|
+
"run complete-stage": route(1, `${project} stage status`, "stage-report dashboard data data-schema-id report alias", "", "alias"),
|
|
93
|
+
"run complete": { ...route(0), retired: "run complete is retired; only an operator may use run override" },
|
|
94
|
+
"run override": route(1, `${project} status reason`, "verdict next-action", "", "", { status: ["cancelled", "failed"] }),
|
|
95
|
+
"run capacity record": route(1, `${project} available-slots`),
|
|
96
|
+
"run recovery inspect": route(1, project),
|
|
97
|
+
"run recovery begin": route(1, `${project} interruption-json`),
|
|
98
|
+
"run recovery seal": route(1, `${project} recovery-id settlement-json`),
|
|
99
|
+
"run recovery capture": route(1, `${project} recovery-id capture-path`),
|
|
100
|
+
"run recovery resume": route(1, `${project} recovery-id daemon-id harness native-session-id`),
|
|
101
|
+
"run recovery accept": { ...route(1, `${project} recovery-id`, lifecycle), contextualPaths: ["project-root"] },
|
|
102
|
+
"run snapshot bootstrap create": route(0, `${project} output`),
|
|
103
|
+
"run snapshot bootstrap restore": route(0, `${project} snapshot`),
|
|
104
|
+
"run snapshot create": route(1, `${project} output`, "recovery-id stage-entry", "candidate incomplete"),
|
|
105
|
+
"run snapshot restore": route(0, `${project} snapshot`, "execution-routing-file recovery-id"),
|
|
106
|
+
"run fork": route(0, "from output engine-version request-id", "integrity-checksum"),
|
|
107
|
+
"run drive status": route(0, control, "after"),
|
|
108
|
+
"run drive launch": route(0, `${control} request-id context-file context-sha256`, "stop-after capture-root"),
|
|
109
|
+
"run drive serve": route(0, `${control} controller-id`),
|
|
110
|
+
"run drive answer": route(0, `${control} request-id pause-id answer-file`),
|
|
111
|
+
"run drive context": route(0, `${control} controller-id request-id stage context-file context-sha256`),
|
|
112
|
+
"run control status": route(0, control),
|
|
113
|
+
"run control reconcile": route(0, `${control} control-id request-id`),
|
|
114
|
+
"run control resume": route(0, `${control} request-id from`, "wait-ms"),
|
|
115
|
+
"run control serve": route(0, `${control} control-id`),
|
|
116
|
+
"run control pause": route(0, `${control} request-id`, "grace-ms wait-ms escalate", "force"),
|
|
117
|
+
"run control stop": route(0, `${control} request-id`, "grace-ms wait-ms escalate", "force"),
|
|
118
|
+
"runtime scope fence": route(0, "scope-id request-id"),
|
|
119
|
+
"runtime scope status": route(0, "scope-id"),
|
|
120
|
+
"runtime scope stop": route(0, "scope-id request-id"),
|
|
121
|
+
"runtime scope control": route(0, "scope-id request-id mode", "manifest-json", "", "", { mode: ["pause", "stop"] }),
|
|
122
|
+
"runtime scope serve": route(0, "scope-id generation"),
|
|
123
|
+
"runtime scope resume": route(0, "scope-id request-id generation capture-key"),
|
|
124
|
+
"runtime scope reconcile": route(0, "scope-id generation request-id"),
|
|
125
|
+
"runtime process check-admission": route(0, "id lease-token"),
|
|
126
|
+
"runtime process start": route(0, `${control} command ports ready-port`, "ready-path ready-timeout-ms"),
|
|
127
|
+
"runtime process stop": route(0, "id lease-token", "grace-ms"),
|
|
128
|
+
"runtime process register": route(0, "kind owner", "lease-ms budget-json project-id run pid process-group-id owner-pid work check operation stdout stderr harness dispatch-barrier role state-dir adapter-executable"),
|
|
129
|
+
"runtime process confirm": route(0, "id lease-token pid", "owner-pid lease-ms process-group-id"),
|
|
130
|
+
"runtime process heartbeat": route(0, "id lease-token", "lease-ms"),
|
|
131
|
+
"runtime process admission": route(0, "id lease-token owner state-dir", "daemon-id operation-id operation native-session-id prompt-sha256"),
|
|
132
|
+
"runtime process release-turn": route(0, "id lease-token owner daemon-id", "operation-id observation-file"),
|
|
133
|
+
"runtime process finish": route(0, "id lease-token state", "reason", "", "", { state: ["stopped", "failed"] }),
|
|
134
|
+
"runtime process status": route(0),
|
|
135
|
+
"runtime process reconcile": route(0, "owner", "grace-ms"),
|
|
136
|
+
"lane status": route(0, project, "lane"),
|
|
137
|
+
"lane waiters": route(0, project, "lane"),
|
|
138
|
+
"lane waiter cancel": route(0, `${project} lane ${worker} reason`),
|
|
139
|
+
"lane workspace set": route(0, `${project} lane path`, "branch"),
|
|
140
|
+
"lane workspace check": route(0, `${project} lane path`),
|
|
141
|
+
"lane lock acquire": route(0, `${project} lane ${worker} reason`, "path ttl"),
|
|
142
|
+
"lane lock heartbeat": route(0, `${project} lane ${worker}`, "path lease-token ttl"),
|
|
143
|
+
"lane lock release": route(0, `${project} lane ${worker} reason`, "path lease-token"),
|
|
144
|
+
"lane lock status": route(0, `${project} lane`),
|
|
145
|
+
"lane lock wait": route(0, `${project} lane ${worker}`, "path timeout poll-interval"),
|
|
146
|
+
"lane lock wait-acquire": route(0, `${project} lane ${worker} reason`, "path timeout poll-interval ttl"),
|
|
147
|
+
"merge-queue status": route(0, "", scoped),
|
|
148
|
+
"merge-queue next": route(0, worker, `${scoped} path`),
|
|
149
|
+
"merge-queue claim": route(1, worker, `${scoped} path`),
|
|
150
|
+
"merge-queue wait-next": route(0, worker, `${scoped} path timeout poll-interval acquire-lock`),
|
|
151
|
+
"merge-queue complete": route(1, `${worker} summary`, `${scoped} path`),
|
|
152
|
+
"merge-queue fail": route(1, `${worker} reason requeue`, `${scoped} path`),
|
|
153
|
+
"merge-queue note": route(1, `${worker} summary`, scoped),
|
|
154
|
+
"merge-queue cancel": route(1, "reason", `${scoped} worker-id path`, "force"),
|
|
155
|
+
"merge serve": route(0, "agent-profile", "poll-seconds max-parallel-projects", "once"),
|
|
156
|
+
"merge server status": route(0),
|
|
157
|
+
"merge server stop": route(1),
|
|
158
|
+
"merge apply": route(1, `${project} work`, lifecycle),
|
|
159
|
+
"merge repair": route(1, project, lifecycle),
|
|
160
|
+
"merge request status": route(1, project),
|
|
161
|
+
"merge request route": route(1, `${project} mode reason`, "", "", "", { mode: ["same_session", "server"] }),
|
|
162
|
+
"merge status": route(0, project, "path"),
|
|
163
|
+
"merge bundle status": route(0, project, "path"),
|
|
164
|
+
"merge bundle claim": route(0, `${project} ${worker}`, "path"),
|
|
165
|
+
"merge bundle complete": route(0, `${project} ${worker} summary`, "path"),
|
|
166
|
+
"merge bundle fail": route(0, `${project} ${worker} reason requeue`, "path"),
|
|
167
|
+
"merge one-shot": route(0, `${project} ${worker}`, "path"),
|
|
168
|
+
"merge-worker status": route(0, project),
|
|
169
|
+
"merge-worker start": route(0, `${project} ${worker}`, "path branch"),
|
|
170
|
+
"merge-worker stop": route(0, `${project} reason`, worker),
|
|
171
|
+
"engine install": route(0, "", "", "force"),
|
|
172
|
+
"engine list": route(0),
|
|
173
|
+
"engine info": route(0, "", "package version"),
|
|
174
|
+
"engine resolve": route(0, "", "root project-root"),
|
|
175
|
+
"engine doctor": route(0, "", "root project-root"),
|
|
176
|
+
"engine bind-run": route(1, `${project} engine-version reason`, "package integrity-checksum"),
|
|
177
|
+
"canon register": route(0, "root"),
|
|
178
|
+
"canon status": route(0, "", "root"),
|
|
179
|
+
"canon resolve": route(0, "", "root"),
|
|
180
|
+
"migration impact": route(0, project, "target-version mode"),
|
|
181
|
+
"migration plan": route(0, project, "source-version target-version run backup-path backup-created-at"),
|
|
182
|
+
"migration report": route(0, project, "source-version target-version run backup-path backup-created-at"),
|
|
183
|
+
"migration verify": route(0, "file"),
|
|
184
|
+
"migration apply": route(0, project, "source-version target-version run backup-path backup-created-at file"),
|
|
185
|
+
"storage migrate-writer": route(0, "database backup", "", "offline"),
|
|
186
|
+
"cleanup scan": route(0, project),
|
|
187
|
+
"cleanup apply": route(0, `${project} plan-file reason`, "", "force"),
|
|
188
|
+
"worktree plan": route(0, "protocol-id", scoped),
|
|
189
|
+
"worktree create": route(0, "protocol-id branch base path", scoped),
|
|
190
|
+
"worktree status": route(0, "protocol-id", scoped),
|
|
191
|
+
"worktree bootstrap": route(0, "protocol-id", scoped),
|
|
192
|
+
"worktree close": route(0, "protocol-id mode", scoped, "", "", { mode: ["keep", "remove"] }),
|
|
193
|
+
"codex home plan": route(0, project, "profile source-home target-home"),
|
|
194
|
+
"codex home init": route(0, project, "profile source-home target-home"),
|
|
195
|
+
"codex home status": route(0, project, "profile"),
|
|
196
|
+
"codex home print-env": route(0, project, "profile"),
|
|
197
|
+
"codex home remove": route(0, `${project} mode`, "profile"),
|
|
198
|
+
"codex hooks print": route(0, project, "target profile"),
|
|
199
|
+
"codex hooks status": route(0, project, "target profile"),
|
|
200
|
+
"codex hooks install": route(0, project, "target profile", "yes"),
|
|
201
|
+
"codex hooks remove": route(0, project, "target profile", "yes"),
|
|
202
|
+
"codex hook handle": route(0, "event", scoped),
|
|
203
|
+
"zcode hook handle": route(0, project),
|
|
204
|
+
"zcode invocation prepare": route(0),
|
|
205
|
+
"zcode event handle": route(0, project),
|
|
206
|
+
"zcode usage ingest": route(0, project),
|
|
207
|
+
"grok event handle": route(0, project),
|
|
208
|
+
"grok usage ingest": route(0, project),
|
|
209
|
+
"opencode event handle": route(0, project),
|
|
210
|
+
"opencode usage ingest": route(0, project),
|
|
211
|
+
"droid event handle": route(0, project),
|
|
212
|
+
"droid usage ingest": route(0, project),
|
|
213
|
+
"agy event handle": route(0, project),
|
|
214
|
+
"agy usage ingest": route(0, project),
|
|
215
|
+
"stat usage": route(0, `${project} run`, "group-by session stage"),
|
|
216
|
+
"stat run sessions ls": route(0, `${project} run`),
|
|
217
|
+
"id next": route(0, `${project} type slug`, "", "", "", { type: ["protocol", "prt", "run", "work", "wrk"] }),
|
|
218
|
+
"integration cmux status": route(0, project),
|
|
219
|
+
"dashboard data": route(0, "", "project project-root protocol", "global"),
|
|
220
|
+
"dashboard render": route(0, "", "project project-root protocol output format"),
|
|
221
|
+
"dashboard render-global": route(0, "", "output format"),
|
|
222
|
+
"dashboard open": route(0, "", "project project-root protocol viewer format"),
|
|
223
|
+
"dashboard refresh": route(0, "", "project project-root protocol open format output", "all"),
|
|
224
|
+
"dashboard refresh-global": route(0, "", "output format"),
|
|
225
|
+
"schema validate": { ...route(0, "schema file", "schema-dir project-root run"), contextualPaths: words("project-root file") },
|
|
226
|
+
"memory permissions preflight": route(0, "root memory-bank flow mode", "tasks")
|
|
227
|
+
};
|
|
228
|
+
export function contextualPathOptionsForLifecycle(operation) {
|
|
229
|
+
const key = lifecycleRouteForOperation(operation);
|
|
230
|
+
return new Set(commandInputs[key]?.contextualPaths ?? []);
|
|
231
|
+
}
|
|
232
|
+
const flag = "__dd_flow_flag__";
|
|
233
|
+
const positiveInteger = new Set(words("limit lease-ms pid owner-pid process-group-id ready-timeout-ms max-parallel-projects expected-revision"));
|
|
234
|
+
const nonnegativeInteger = new Set(words("after generation wait-ms grace-ms available-slots"));
|
|
235
|
+
const positiveNumber = new Set(words("ttl poll-interval poll-seconds"));
|
|
236
|
+
const booleans = new Set(words("write close-sessions cancel-queue release-locks user-required requeue acquire-lock"));
|
|
237
|
+
export function prepareCommandRoute(args) {
|
|
238
|
+
const parsed = parseCommandArgs(args);
|
|
239
|
+
const key = Object.keys(commandInputs).filter(key => key.split(" ").every((part, index) => parsed.positional[index] === part))
|
|
240
|
+
.sort((a, b) => b.split(" ").length - a.split(" ").length)[0];
|
|
241
|
+
const reject = (message, parameter) => { throw new AppError("usage", message, 2, { phase: "prepare", effect: "no_effect", recoverable: true, ...(parameter ? { parameter } : {}) }); };
|
|
242
|
+
if (!key)
|
|
243
|
+
return reject("Unknown command; use dd-flow --help");
|
|
244
|
+
const contract = commandInputs[key];
|
|
245
|
+
if (contract.retired)
|
|
246
|
+
reject(contract.retired);
|
|
247
|
+
const prefixLength = key.split(" ").length;
|
|
248
|
+
const positionCount = parsed.positional.length - prefixLength;
|
|
249
|
+
if (positionCount < contract.positions[0] || positionCount > contract.positions[1])
|
|
250
|
+
reject(`${key} expects ${contract.positions[0] === contract.positions[1] ? contract.positions[0] : `${contract.positions[0]}..${contract.positions[1]}`} positional argument(s)`);
|
|
251
|
+
for (const [name, values] of parsed.options) {
|
|
252
|
+
if (key.startsWith("merge-queue ") && name === "session-id")
|
|
253
|
+
reject("--session-id is no longer accepted on merge-queue commands; use --worker-id", name);
|
|
254
|
+
const upgrade = ["compatibility-mode", "mb-upgrade-mode"].includes(name);
|
|
255
|
+
if (upgrade && !isUpgradeAllowlisted(args))
|
|
256
|
+
reject(`${key} does not support explicit upgrade mode`, name);
|
|
257
|
+
if (!upgrade && !contract.values.includes(name) && !contract.switches.includes(name))
|
|
258
|
+
reject(`${key} does not accept --${name}`, name);
|
|
259
|
+
if (values.length > 1 && !contract.repeatable.includes(name))
|
|
260
|
+
reject(`--${name} must occur once`, name);
|
|
261
|
+
for (const value of values) {
|
|
262
|
+
if (contract.switches.includes(name) || name === "mb-upgrade-mode") {
|
|
263
|
+
if (value !== flag)
|
|
264
|
+
reject(`--${name} is a switch and does not take a value`, name);
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (value === flag || !value.trim())
|
|
268
|
+
reject(`--${name} requires a non-empty value`, name);
|
|
269
|
+
if (name === "compatibility-mode" && value !== "mb-upgrade")
|
|
270
|
+
reject("--compatibility-mode must be mb-upgrade", name);
|
|
271
|
+
const choices = contract.enums[name];
|
|
272
|
+
if (choices && !choices.includes(key === "id next" && name === "type" ? value.toLowerCase() : value))
|
|
273
|
+
reject(`--${name} must be ${choices.join(" or ")}`, name);
|
|
274
|
+
if (booleans.has(name) && !["true", "false"].includes(value))
|
|
275
|
+
reject(`--${name} must be true or false`, name);
|
|
276
|
+
const number = Number(value);
|
|
277
|
+
if (positiveInteger.has(name) && (!/^[0-9]+$/.test(value) || !Number.isSafeInteger(number) || number <= 0)
|
|
278
|
+
|| nonnegativeInteger.has(name) && (!/^[0-9]+$/.test(value) || !Number.isSafeInteger(number) || number < 0)
|
|
279
|
+
|| positiveNumber.has(name) && (!Number.isFinite(number) || number <= 0)
|
|
280
|
+
|| name === "timeout" && (!Number.isFinite(number) || number < 0)
|
|
281
|
+
|| name === "available-slots" && number > 15)
|
|
282
|
+
reject(`Invalid numeric value for --${name}`, name);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
for (const name of contract.required)
|
|
286
|
+
if (!parsed.options.has(name))
|
|
287
|
+
reject(`Missing required option: --${name}`, name);
|
|
288
|
+
for (const aliases of [
|
|
289
|
+
["root", "project-root"], ["payload-file", "json-file"],
|
|
290
|
+
["payload-file", "payload-json", "payload-base64"], ["semantic-file", "data", "result-file", "result-stdin"],
|
|
291
|
+
["stage-report", "dashboard"], ["task-file", "plan-item"], ["project", "project-root"],
|
|
292
|
+
["intake-file", "intake-stdin", "context-file"], ["question-file", "question-stdin"], ["answer-file", "answer-stdin"],
|
|
293
|
+
["summary-file", "summary-stdin"], ["task-file", "task-stdin"], ["reason", "reason-file"]
|
|
294
|
+
]) {
|
|
295
|
+
const present = aliases.filter(name => parsed.options.has(name));
|
|
296
|
+
if (present.length > 1)
|
|
297
|
+
reject(`Use only one of ${present.map(name => `--${name}`).join(", ")}`);
|
|
298
|
+
}
|
|
299
|
+
if (contract.values.includes("retry-check") && parsed.options.has("retry-check") !== (parsed.options.has("reason") || parsed.options.has("reason-file")))
|
|
300
|
+
reject("--retry-check requires exactly one of --reason or --reason-file");
|
|
301
|
+
// Retain the dispatcher's historic offsets for nested action positions.
|
|
302
|
+
const family = parsed.positional[0];
|
|
303
|
+
const singleWord = ["status", "version", "transition"].includes(family);
|
|
304
|
+
return { key, family, command: singleWord ? undefined : parsed.positional[1], parsed: { options: parsed.options, positional: parsed.positional.slice(singleWord ? 1 : 2) } };
|
|
305
|
+
}
|
package/dist/cli/help.js
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
const helpPages = new Map([
|
|
2
|
+
["runtime scope", `Usage:
|
|
3
|
+
dd-flow runtime scope fence --scope-id EVAL_ID --request-id ID --json
|
|
4
|
+
dd-flow runtime scope status --scope-id EVAL_ID --json
|
|
5
|
+
dd-flow runtime scope stop --scope-id EVAL_ID --request-id ID --json
|
|
6
|
+
dd-flow runtime scope control --scope-id EVAL_ID --request-id ID --mode pause|stop [--manifest-json JSON] --json
|
|
7
|
+
dd-flow runtime scope resume --scope-id EVAL_ID --request-id ID --generation N --capture-key SHA256 --json
|
|
8
|
+
dd-flow runtime scope reconcile --scope-id EVAL_ID --generation N --request-id ID --json
|
|
9
|
+
|
|
10
|
+
Use the EVAL manifest's retained DD_FLOW_RESOURCE_HOME. Commands select exactly
|
|
11
|
+
one scope across its registered runtime homes; neighboring scopes are untouched.
|
|
12
|
+
fence durably blocks new provider turns and owned baseline checks. It does not
|
|
13
|
+
stop existing work. status reports retained ownership, not proof of settlement.
|
|
14
|
+
stop fences first and requests owned daemon-tree and baseline-process cleanup.
|
|
15
|
+
Inspect settled and each node's evidence: ok alone does not prove cleanup.
|
|
16
|
+
Unproven ownership or cleanup remains pending; repeat stop to observe settlement.
|
|
17
|
+
The fence/stop route is terminal cancellation and has no resume command.
|
|
18
|
+
control records recoverable scope intent and starts a detached drain owner.
|
|
19
|
+
The EVAL resolver supplies a runtime-scope-manifest@1 declaration with the source
|
|
20
|
+
manifest path, SHA-256 and execution IDs, including queued executions. Declaration
|
|
21
|
+
changes are rejected. resume accepts the exact captured generation and starts
|
|
22
|
+
detached recovery preparation. It does not yet release scope admission: inspect
|
|
23
|
+
dispatch_blocked and pending reasons; accepted preparation is not resumed work.
|
|
24
|
+
RUN pause/stop/resume uses dd-flow run control.`],
|
|
25
|
+
["storage", `Usage:
|
|
26
|
+
dd-flow storage migrate-writer --database ABSOLUTE_DB --backup NEW_ABSOLUTE_FILE --offline --json
|
|
27
|
+
|
|
28
|
+
Drain all local and external runtime owners before using --offline. This command
|
|
29
|
+
migrates one existing database, not a whole runtime or retained provider Session.
|
|
30
|
+
It refuses unresolved ownership rows, preserves a verified WAL-safe backup, and
|
|
31
|
+
fences unaware old writers. It does not initialize the default DD_FLOW_HOME.
|
|
32
|
+
The backup path must be new; existing backups are never overwritten. An exact
|
|
33
|
+
retry of a committed migration returns its receipt after verifying the backup.
|
|
34
|
+
If no committed receipt exists, retain the failed backup and choose a new path.`],
|
|
2
35
|
[
|
|
3
36
|
"",
|
|
4
37
|
`dd-flow - mechanical control layer for dd-flow workflows
|
|
@@ -33,11 +66,14 @@ Core commands:
|
|
|
33
66
|
session register/status/stop Register flow sessions and stop workers.
|
|
34
67
|
dashboard data/render/open/refresh Render, refresh, open, and inspect project/global dashboards.
|
|
35
68
|
schema validate Validate canonical dd-flow JSON data contracts.
|
|
69
|
+
storage migrate-writer Explicitly back up and fence a drained SQLite store.
|
|
70
|
+
runtime scope fence/status/stop Fence, inspect, or cancel one retained EVAL scope.
|
|
36
71
|
memory permissions preflight Check Memory Bank write/read permissions.
|
|
37
72
|
integration cmux status Inspect optional cmux integration.
|
|
38
73
|
codex home/hooks/hook Manage Codex homes, hooks, and hook events.
|
|
39
74
|
zcode event/usage Ingest trusted zcode-acp lifecycle and usage evidence.
|
|
40
75
|
grok event/usage Ingest trusted Grok Build lifecycle and usage evidence.
|
|
76
|
+
droid event/usage Ingest trusted Factory Droid lifecycle and physical usage evidence.
|
|
41
77
|
opencode event/usage Ingest trusted OpenCode lifecycle and usage evidence.
|
|
42
78
|
agy event/usage Ingest trusted Antigravity CLI lifecycle and usage evidence.
|
|
43
79
|
worktree plan/create/status Record Worktrunk-backed feature worktrees.
|
|
@@ -152,12 +188,18 @@ Usage:
|
|
|
152
188
|
dd-flow run start --project-root <root> [--workspace-root <checkout>] --flow-kind <kind> --subject-type <type> --subject-id <id> --slug <slug> [--preset compact|normal|full] [--task-profile-file <file>] [--protocol-override-file <file>] [--flag key=value] [--next-action <text>] --json
|
|
153
189
|
dd-flow id next --type protocol|run --project-root <root> --slug <slug> --json
|
|
154
190
|
dd-flow run status <RUN-ID|RUN-short-id> --project-root <root> --json
|
|
191
|
+
dd-flow run control status --run <RUN-ID> --project-root <root> --json
|
|
192
|
+
dd-flow run control reconcile --run <RUN-ID> --project-root <root> --control-id <ID> --request-id <ID> --json
|
|
193
|
+
dd-flow run drive launch --run <RUN-ID> --project-root <root> --request-id <id> --context-file <file> --context-sha256 <sha256> [--stop-after <stage>] [--capture-root <directory>] --json
|
|
194
|
+
dd-flow run drive status --run <RUN-ID> --project-root <root> [--after <sequence>] --json
|
|
155
195
|
dd-flow run list --project-root <root> --json
|
|
156
|
-
dd-flow run prepare-vnext-specify --project-root <root> --slug <slug> --json
|
|
157
|
-
dd-flow run
|
|
158
|
-
dd-flow run snapshot
|
|
196
|
+
dd-flow run prepare-vnext-specify --project-root <root> --slug <slug> [--execution-routing-file <file>] --json
|
|
197
|
+
dd-flow run recovery inspect|begin|seal|capture|resume <RUN-ID|RUN-short-id> --project-root <root> --json
|
|
198
|
+
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
|
+
dd-flow run snapshot restore --snapshot <directory> --project-root <prepared-root> [--recovery-id <RCV-ID>] --json
|
|
159
200
|
dd-flow run snapshot bootstrap create --project-root <root> --output <directory> --json
|
|
160
201
|
dd-flow run snapshot bootstrap restore --snapshot <directory> --project-root <prepared-root> --json
|
|
202
|
+
dd-flow run fork --from <sealed-stage-entry-snapshot> --output <empty-directory> --engine-version <exact-version> --request-id <id> [--integrity-checksum <sha256>] --json
|
|
161
203
|
dd-flow run timeline <RUN-ID|RUN-short-id> --project-root <root> --json
|
|
162
204
|
dd-flow stat usage --run <RUN-ID|RUN-short-id> --project-root <root> [--stage <stage[,stage...]>] [--session <session-id>] --json
|
|
163
205
|
dd-flow stat run sessions ls --run <RUN-ID|RUN-short-id> --project-root <root> --json
|
|
@@ -169,7 +211,12 @@ Usage:
|
|
|
169
211
|
|
|
170
212
|
RUN-* is the execution envelope for one concrete flow launch. Semantic truth remains in protocol, experiment, DEF, scenario, evidence, and Memory Bank documents. New run artifacts are stored under DD_FLOW_HOME/projects/<PRJ-ID-slug>/runs/<RUN-ID-slug>/ with one run.json projection and an append-only timeline.jsonl. Timeline is the compact full run report: summary is always present, while --hide may suppress bulky sections. Use \`dd-flow stat usage --run …\` to reread registered local Codex transcript counters and tool-call facts and refresh the current usage projection; unavailable data is explicit rather than zero.
|
|
171
213
|
|
|
172
|
-
run prepare-vnext-specify
|
|
214
|
+
run start and prepare-vnext-specify accept --execution-routing-file for vNext RUNs: dd-flow/execution-routing@1 with an execution object selects the complete routing policy from existing agent-profiles. RUN creation freezes the input and selected profiles without changing project settings.
|
|
215
|
+
run snapshot restore also accepts --execution-routing-file for a new stage-entry experiment. Its fresh DD_FLOW_HOME may contain only agent-profiles and the empty database; selected profiles are read before import, previous RUN policy is archived, and existing Work overrides must resolve against the selected frozen profiles. Recovery imports reject this option.
|
|
216
|
+
run fork restores one sealed stage-entry snapshot to an isolated project and DD_FLOW_HOME, archives source authority, then binds an exact engine only in that copy. It is idempotent by request ID and output receipt; it never resumes a provider session or changes its source RUN.
|
|
217
|
+
run prepare-vnext-specify allocates an otherwise unstarted vNext RUN for the canonical SPECIFY entry checkpoint. run recovery makes an interrupted RUN read-only, requires an explicit settled-tree receipt, captures immutable recovery evidence, then explicitly returns delegated Work to the ready graph. run snapshot is the eval-only checkpoint boundary: it snapshots one quiescent RUN, its dedicated DD_FLOW_HOME, and the exact project tree including its Git repository, then restores them into a fresh dedicated runtime. It is not a general runtime backup command and fails closed for a shared runtime.
|
|
218
|
+
|
|
219
|
+
Managed drive is not yet native-provider qualified. With --capture-root, its detached controller fences RUN writers and captures each completed Stage before dispatching its successor. The capture root must be outside the runtime, project and workspace. Status events expose boundary_captured receipts; capturing means writers are still fenced, and capture_failed retains the fence for operator reconciliation. External snapshot creation is rejected while a managed controller owns a live RUN.
|
|
173
220
|
|
|
174
221
|
Examples:
|
|
175
222
|
dd-flow run start --project-root "$PWD" --flow-kind mb_sdlc --subject-type protocol --subject-id PRT-001-demo --slug demo --json
|
|
@@ -184,16 +231,22 @@ Examples:
|
|
|
184
231
|
Usage:
|
|
185
232
|
dd-flow stage start <RUN-ID|RUN-short-id> --project-root <root> --stage <name> [--dir <NN-stage-slug>] [--require-session-binding] --json
|
|
186
233
|
dd-flow stage start --bootstrap --project-root <root> --stage specify --subject <safe-subject> (--intake-file <path>|--intake-stdin) [--require-session-binding] --json
|
|
187
|
-
dd-flow stage pause <RUN-ID|RUN-short-id> --project-root <root> --stage <name> --work <WORK-ID> --question-stdin --json
|
|
188
|
-
dd-flow stage resume <RUN-ID|RUN-short-id> --project-root <root> --stage <name> --work <WORK-ID> --answer-stdin --json
|
|
189
|
-
|
|
234
|
+
dd-flow stage pause <RUN-ID|RUN-short-id> --project-root <root> --stage <name> --work <WORK-ID> (--question-file <path>|--question-stdin) --json
|
|
235
|
+
dd-flow stage resume <RUN-ID|RUN-short-id> --project-root <root> --stage <name> --work <WORK-ID> (--answer-file <path>|--answer-stdin) --json
|
|
236
|
+
|
|
237
|
+
Managed resume commands restore the accepted answer file from runtime state. Execute the returned command without adding an answer path or recreating the answer. The explicit answer flags above are for unmanaged calls.
|
|
238
|
+
Path aliases @project, @workspace and @run are supported only in declared CLI path parameters and require a uniquely bound context. File-writing tools use physical paths. Both --option value and --option=value are accepted; quoted or escaped aliases are normalized identically. Pre-RUN bootstrap paths and external schema directories require physical paths.
|
|
239
|
+
An aggregate CODE/CODE-REVIEW failure may return continuation.kind=repair_required: its repair Work is already registered. End the coordinator turn and let the controller dispatch the fresh child; do not recreate the repair. A recovery retry uses --retry-check <receipt> --reason-file <recovery.json>, containing only {"reason":"actual environment recovery evidence"}. Legacy --reason remains accepted, but cannot be combined with --reason-file. A needs_input continuation is not yet executable: write its requested file first, then use command_after_input.
|
|
240
|
+
dd-flow stage block <RUN-ID|RUN-short-id> --project-root <root> --stage <name> --work <WORK-ID> --kind engine|harness|environment --code <code> (--summary-file <path>|--summary-stdin) [--retryable] --json
|
|
190
241
|
dd-flow stage unblock <RUN-ID|RUN-short-id> --project-root <root> --stage <name> --work <WORK-ID> --json
|
|
191
242
|
dd-flow stage fanout status <RUN-ID|RUN-short-id> --project-root <root> --stage <name> --json
|
|
192
243
|
dd-flow stage fanout dispatch <RUN-ID|RUN-short-id> --project-root <root> --stage <name> --json
|
|
244
|
+
dd-flow stage fanout reconcile <RUN-ID> --project-root <root> --stage <name> --observations-file <native-observations.json> --json
|
|
245
|
+
dd-flow stage native observe <RUN-ID> --project-root <root> --stage <name> --observations-file <native-observations.json> --json
|
|
193
246
|
dd-flow stage finish <RUN-ID|RUN-short-id> --project-root <root> --stage <name> [--semantic-file <RUN-local-json>] --json
|
|
194
247
|
dd-flow stage finish <RUN-ID|RUN-short-id> --project-root <root> --stage specify (--result-file <RUN-local-specify.json>|--result-stdin) --outcome <specified|failed|cancelled> --json
|
|
195
248
|
|
|
196
|
-
stage start is the worker's first practical flow command. It performs deterministic setup and returns a ready-to-use, stage-specific work packet with trusted runtime facts, compatibility and permission preflight, aliases, write boundary and exact lifecycle commands. A material user question uses stage pause, not stage finish: pause leaves the same stage, Work, Session and attempt open and returns the exact resume command. Engine, harness and environment failures use stage block and never create HITL. On the next Turn, pass a complete user answer to stage resume, or repair an external blocker and call its returned stage unblock command. stage fanout is read-only orchestration state plus the stage's deterministic Work materialization action for an external runner; it never makes product decisions. stage finish is reserved for actual stage completion and generates the final deterministic reports.
|
|
249
|
+
stage start is the worker's first practical flow command. It performs deterministic setup and returns a ready-to-use, stage-specific work packet with trusted runtime facts, compatibility and permission preflight, aliases, write boundary and exact lifecycle commands. Managed commands use scoped RUN/Work aliases and @project; their internal invocation UUID is bound by the native hook and is intentionally not model-facing. @ aliases apply only to declared dd-flow path arguments, not to shell tools. A material user question uses stage pause, not stage finish: pause leaves the same stage, Work, Session and attempt open and returns the exact resume command. Engine, harness and environment failures use stage block and never create HITL. On the next Turn, pass a complete user answer to stage resume, or repair an external blocker and call its returned stage unblock command. stage fanout is read-only orchestration state plus the stage's deterministic Work materialization action for an external runner; it never makes product decisions. stage finish is reserved for actual stage completion and generates the final deterministic reports. Unmanaged operator calls retain explicit project and runtime selection.`
|
|
197
250
|
],
|
|
198
251
|
[
|
|
199
252
|
"work",
|
|
@@ -203,8 +256,9 @@ Usage:
|
|
|
203
256
|
dd-flow work ls (--run <RUN-ID>|--parent <WORK-ID>) [--ready] --json
|
|
204
257
|
dd-flow work show <WORK-ID> --json
|
|
205
258
|
dd-flow work start <WORK-ID> --project-root <root> --json
|
|
259
|
+
dd-flow work launch <WORK-ID> [--stage <name>] --json
|
|
206
260
|
dd-flow work finish <WORK-ID> (--result-file <path>|--result-stdin) --project-root <root> --json
|
|
207
|
-
dd-flow work repair add --run <RUN-ID> (--from-check <CHECK-ID>|--from-unresolved <gap> --verification-file <file>) --origin-work <WORK-ID>... --task-stdin --project-root <root> --json
|
|
261
|
+
dd-flow work repair add --run <RUN-ID> (--from-check <CHECK-ID>|--from-unresolved <gap> --verification-file <file>) --origin-work <WORK-ID>... (--task-file <path>|--task-stdin) --project-root <root> --json
|
|
208
262
|
|
|
209
263
|
CODE workers receive their full accepted packet from work start. work finish validates the result and executes the packet's focused checks before completion. A failed aggregate CODE gate or unresolved semantic verification creates a repair Work from the selected completed origin context and retained evidence. Its planned write areas are coordination hints only; the repair may change any necessary project file inside its RUN workspace.`
|
|
210
264
|
],
|
|
@@ -369,11 +423,12 @@ Usage:
|
|
|
369
423
|
dd-flow merge request status <MRG-ID> --project-root <root> --json
|
|
370
424
|
dd-flow merge request route <MRG-ID> --mode same_session|server --reason <text> --project-root <root> --json
|
|
371
425
|
dd-flow merge apply <MRG-ID> --work <WRK-ID> --project-root <root> --json --progress-jsonl
|
|
426
|
+
dd-flow merge repair <MRG-ID> --project-root <root> --json
|
|
372
427
|
dd-flow merge serve --agent-profile <id> [--once] [--poll-seconds <n>] [--max-parallel-projects <n>] --progress-jsonl
|
|
373
428
|
dd-flow merge server status --json
|
|
374
429
|
dd-flow merge server stop <MSV-ID> --json
|
|
375
430
|
|
|
376
|
-
CODE or CODE-REVIEW creates one MRG request and child MERGE Work. stage start waits in the shared project FIFO, reports progress, locks the execution target baseline and returns the exact apply/finish commands. merge apply is the only supported initial Git mutation. merge serve is a deterministic dispatcher: it launches a fresh Session through the configured harness adapter but does not perform agent work itself. It preserves FIFO inside each project and may serve different projects concurrently up to the explicit bound.`
|
|
431
|
+
CODE or CODE-REVIEW creates one MRG request and child MERGE Work. stage start waits in the shared project FIFO, reports progress, locks the execution target baseline and returns the exact apply/finish commands. merge apply is the only supported initial Git mutation. If its integration gate fails, merge repair restores the target baseline and creates a source CODE → independent CODE-REVIEW → replacement-MRG cycle; it never patches product code in the integration workspace. merge serve is a deterministic dispatcher: it launches a fresh Session through the configured harness adapter but does not perform agent work itself. It preserves FIFO inside each project and may serve different projects concurrently up to the explicit bound.`
|
|
377
432
|
],
|
|
378
433
|
[
|
|
379
434
|
"cleanup",
|
|
@@ -536,17 +591,38 @@ handler resolves the registered project from cwd. The option is only a manual
|
|
|
536
591
|
override.
|
|
537
592
|
|
|
538
593
|
Managed homes isolate dd-flow hooks while sharing selected Codex state from the source home.`
|
|
594
|
+
],
|
|
595
|
+
[
|
|
596
|
+
"zcode hook",
|
|
597
|
+
`dd-flow zcode hook - handle a synchronous native ZCode PreToolUse callback
|
|
598
|
+
|
|
599
|
+
Usage:
|
|
600
|
+
dd-flow zcode hook handle --project-root <root> --json
|
|
601
|
+
|
|
602
|
+
The managed ZCode native hook supplies the callback on stdin. It records the
|
|
603
|
+
receipt before returning a rewritten tool input with --hook-event-id.`
|
|
539
604
|
],
|
|
540
605
|
[
|
|
541
606
|
"zcode event",
|
|
542
|
-
`dd-flow zcode event - ingest a zcode-acp session/update notification
|
|
607
|
+
`dd-flow zcode event - ingest a zcode-acp session/update notification as evidence
|
|
543
608
|
|
|
544
609
|
Usage:
|
|
545
610
|
dd-flow zcode event handle --project-root <root> --json
|
|
546
611
|
dd-flow zcode usage ingest --project-root <root> --json
|
|
547
612
|
|
|
548
|
-
Both payloads are read from stdin.
|
|
549
|
-
|
|
613
|
+
Both payloads are read from stdin. Native hooks own lifecycle admission; ACP
|
|
614
|
+
events and usage retain secondary evidence for RUN accounting.`
|
|
615
|
+
],
|
|
616
|
+
[
|
|
617
|
+
"droid event",
|
|
618
|
+
`dd-flow droid event - ingest a controlled Factory Droid Execute hook
|
|
619
|
+
|
|
620
|
+
Usage:
|
|
621
|
+
dd-flow droid event handle --project-root <root> --json
|
|
622
|
+
dd-flow droid usage ingest --project-root <root> --json
|
|
623
|
+
|
|
624
|
+
Reads trusted adapter JSON from stdin. Usage requires physical_session scope and explicit completeness.
|
|
625
|
+
`
|
|
550
626
|
],
|
|
551
627
|
[
|
|
552
628
|
"opencode event",
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { performance } from "node:perf_hooks";
|
|
3
|
+
import { parseCommandArgs, parseLifecycleCommand, lifecycleCommandFromPayload, continuationCommand } from "../services/lifecycle-command.js";
|
|
4
|
+
import { errorRecord, AppError } from "../shared/errors.js";
|
|
5
|
+
import { parseJsonObject } from "../shared/json.js";
|
|
6
|
+
const workerFile = fileURLToPath(import.meta.url);
|
|
7
|
+
const ingressBudgetMs = 20_000; // Native host timeout is 30s; this includes cold module/DB open.
|
|
8
|
+
/** Lightweight entry: unrelated hooks never load the router or open storage. */
|
|
9
|
+
export async function runHookIngress(args) {
|
|
10
|
+
try {
|
|
11
|
+
const parsed = parseCommandArgs(args.slice(3));
|
|
12
|
+
for (const [key, values] of parsed.options)
|
|
13
|
+
if (!["event", "project-root", "json"].includes(key) || values.length !== 1)
|
|
14
|
+
throw new AppError("usage", `Invalid hook option: ${key}`, 2);
|
|
15
|
+
const event = parsed.options.get("event")?.[0];
|
|
16
|
+
if (!event?.trim() || event === "__dd_flow_flag__" || parsed.positional.length)
|
|
17
|
+
throw new AppError("usage", "Hook ingress requires --event with a value", 2);
|
|
18
|
+
const root = parsed.options.get("project-root")?.[0];
|
|
19
|
+
if (root !== undefined && (!root.trim() || root === "__dd_flow_flag__"))
|
|
20
|
+
throw new AppError("usage", "--project-root requires a value", 2);
|
|
21
|
+
if (parsed.options.has("json") && parsed.options.get("json")?.[0] !== "__dd_flow_flag__")
|
|
22
|
+
throw new AppError("usage", "--json does not take a value", 2);
|
|
23
|
+
let stdin = "";
|
|
24
|
+
for await (const chunk of process.stdin) {
|
|
25
|
+
stdin += String(chunk);
|
|
26
|
+
if (Buffer.byteLength(stdin) > 1_048_576)
|
|
27
|
+
throw new AppError("native_hook_response_invalid", "Hook input exceeds 1 MiB", 1);
|
|
28
|
+
}
|
|
29
|
+
const payload = parseJsonObject(stdin || "{}", "native hook stdin");
|
|
30
|
+
const command = lifecycleCommandFromPayload(payload);
|
|
31
|
+
if (event !== "PreToolUse" || !command || (parseLifecycleCommand(command).kind === "none" && !continuationCommand(command))) {
|
|
32
|
+
process.stdout.write("{}\n");
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
const started = performance.now();
|
|
36
|
+
const { invokeNativeHook } = await import("../harness-runtime/lib/native-hook-command.mjs");
|
|
37
|
+
const result = await invokeNativeHook({ bin: workerFile, args, payload, home: process.env.DD_FLOW_HOME, timeoutMs: ingressBudgetMs });
|
|
38
|
+
const { timing, ...output } = result;
|
|
39
|
+
process.stderr.write(`${JSON.stringify({ kind: "hook_ingress", total_ms: Math.round(performance.now() - started), ...timing })}\n`);
|
|
40
|
+
process.stdout.write(`${JSON.stringify(output)}\n`);
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
const record = errorRecord(error);
|
|
45
|
+
process.stderr.write(`${JSON.stringify({ ok: false, error: record })}\n`);
|
|
46
|
+
return record.exitCode;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// A bounded CLI subprocess, not a detached writer: its successful reply follows COMMIT.
|
|
50
|
+
if (process.argv[1] === workerFile) {
|
|
51
|
+
try {
|
|
52
|
+
let stdin = "";
|
|
53
|
+
for await (const chunk of process.stdin)
|
|
54
|
+
stdin += String(chunk);
|
|
55
|
+
const payload = parseJsonObject(stdin, "native hook stdin");
|
|
56
|
+
const started = performance.now();
|
|
57
|
+
const { verifyCodexHookDelivery } = await import("../services/codex-hook-delivery.js");
|
|
58
|
+
const proof = await verifyCodexHookDelivery(process.env, payload);
|
|
59
|
+
const verified = performance.now();
|
|
60
|
+
const [{ createContext }, { handleCodexHook }] = await Promise.all([import("../runtime/context.js"), import("../services/hooks.js")]);
|
|
61
|
+
const loaded = performance.now();
|
|
62
|
+
const context = createContext(process.env, "hook");
|
|
63
|
+
const opened = performance.now();
|
|
64
|
+
try {
|
|
65
|
+
if (proof)
|
|
66
|
+
context.codexHookProof = proof;
|
|
67
|
+
const parsed = parseCommandArgs(process.argv.slice(5));
|
|
68
|
+
const projectRoot = parsed.options.get("project-root")?.[0];
|
|
69
|
+
const result = handleCodexHook(context, { event: "PreToolUse", ...(projectRoot ? { projectRoot } : {}), stdin });
|
|
70
|
+
process.stdout.write(`${JSON.stringify({ ...(result.hookSpecificOutput ? { hookSpecificOutput: result.hookSpecificOutput } : {}), timing: {
|
|
71
|
+
verify_ms: Math.round(verified - started), load_ms: Math.round(loaded - verified), open_ms: Math.round(opened - loaded), receipt_ms: Math.round(performance.now() - opened)
|
|
72
|
+
} })}\n`);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
context.db.close?.();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
process.stderr.write(`${JSON.stringify({ ok: false, error: errorRecord(error) })}\n`);
|
|
80
|
+
process.exitCode = 1;
|
|
81
|
+
}
|
|
82
|
+
}
|